├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Vagrantfile
├── composer.json
├── phpunit.xml.dist
├── src
└── RescueTime
│ ├── .Activity.php.swp
│ ├── Activity.php
│ ├── Client.php
│ ├── DailyReport.php
│ ├── HttpClient.php
│ └── RequestQueryParameters.php
└── tests
├── RescueTime
└── Tests
│ ├── ClientTest.php
│ └── Fakes
│ ├── daily_report.json
│ ├── interval.json
│ ├── member.json
│ └── rank.json
└── bootstrap.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Ingore Vagrant stuff
4 | *.box
5 | .cache/
6 | .vagrant
7 | .bashrc
8 | .bash_history
9 | .sudo_as_admin_successful
10 |
11 | # Ignore Composer stuff
12 | .composer/
13 | vendor/
14 | composer.lock
15 |
16 | # Ignore IDE stuff
17 | .idea
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - 7.0
8 |
9 | before_script:
10 | - composer install --dev
11 |
12 | script:
13 | - phpunit
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Getting Started (Vagrant Setup)
2 |
3 | 1. Install Git
4 | 2. Install VirtualBox: https://www.virtualbox.org/wiki/Downloads
5 | 3. Install Vagrant: http://www.vagrantup.com/ (version 1.2.2+ or later)
6 | 4. Open a terminal
7 | 5. Clone the project: `git clone https://github.com/borivojevic/rescuetime-api-php.git`
8 | 6. Enter the project directory: `cd rescuetime-api-php`
9 |
10 | ### Using Vagrant
11 |
12 | When you're ready to start working, boot the VM:
13 |
14 | ```
15 | vagrant up
16 | ```
17 |
18 | The first time you do this Vagrant will have to download and install VM image which can take ~15 minutes or more depending on internet connection speed.
19 |
20 | When machine boots up ssh into it by typing:
21 |
22 | ```
23 | vagrant ssh
24 | # password: vagrant
25 | ```
26 |
27 | **On Windows**: Use : ssh vagrant@127.0.0.1 -p 2222
28 |
29 |
30 | ### Making Changes
31 |
32 | The application code is found in vagrant home directory at /home/vagrant
33 |
34 | The very first time you'll have to install application dependencies:
35 |
36 | ```
37 | sudo composer self-update
38 | composer install
39 | ```
40 |
41 | Basic Workflow: Run vagrant machine >> Update repository >> Edit >> Send GitHub pull request
42 |
43 | 1. Update repository
44 | 1. `cd /home/vagrant`
45 | 1. `git checkout master`
46 | 1. `git pull`
47 | 1. Make changes to RescueTime API
48 | 1. `cd /home/vagrant`
49 | 1. (Make changes)
50 | 1. `git commit ...`
51 | 1. (Make sure all tests pass. See [testing](#testing))
52 | 1. `git push`
53 | 1. Submit pull request to master repository
54 | 1. [Using pull requests](https://help.github.com/articles/using-pull-requests)
55 | 1. [Creating a pull request](https://help.github.com/articles/creating-a-pull-request)
56 |
57 | ### Testing
58 |
59 | To run unit test suite type:
60 |
61 | ```
62 | phpunit
63 | ```
64 |
65 | To run coding standard tests type:
66 |
67 | ```
68 | phpcs --standard=PSR2 src/
69 | phpcs --standard=PSR2 tests/
70 | ```
71 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Mirko Borivojevic
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/borivojevic/rescuetime-api-php)
2 | [](https://scrutinizer-ci.com/g/borivojevic/rescuetime-api-php/)
3 | [](https://scrutinizer-ci.com/g/borivojevic/rescuetime-api-php/)
4 | [](https://packagist.org/packages/borivojevic/rescuetime)
5 |
6 | rescuetime-api-php
7 | ========
8 |
9 | PHP wrapper library for [RescueTime][] API
10 |
11 | At this point RescueTime API provides single endpoint to fetch detailed and complicated data. The data is read-only through the API.
12 |
13 | Initial release of RescueTime API is targeted at bringing developers the prepared and pre-organized data structures already familiar through the reporting views of www.rescuetime.com.
14 | Keep in mind this is a draft interface, and may change in the future. RescueTime do intend to version the interfaces though, so it is likely forward compatible.
15 |
16 | ### Installation ###
17 |
18 | Recommend way to install this package with [Composer][]. Add borivojevic/rescuetime-api-php to your composer.json file.
19 |
20 | ``` json
21 | {
22 | "require": {
23 | "borivojevic/rescuetime": "2.*"
24 | }
25 | }
26 | ```
27 |
28 | To install composer run:
29 |
30 | ```
31 | curl -s http://getcomposer.org/installer | php
32 | ```
33 |
34 | To install composer dependences run:
35 |
36 | ```
37 | php composer.phar install
38 | ```
39 |
40 | You can autoload all dependencies by adding this to your code:
41 |
42 | ```
43 | require 'vendor/autoload.php';
44 | ```
45 |
46 | ### Usage ###
47 |
48 | The main entry point of the library is the `RescueTime\Client` class. API methods require to be signed with valid `api_key` parameter which you have to provide as a first argument of the constructor. You can obtain RescueTime API key on [API Key Management][] console page.
49 |
50 | ``` php
51 | getActivities(new Params(['perspective' => 'rank']));
60 |
61 | foreach ($activities as $activity) {
62 | echo $activity->getActivityName();
63 | echo $activity->getProductivity();
64 | }
65 |
66 | // Fetch activities for past week
67 | $activities = $client->getActivities(
68 | new Params([
69 | 'perspective' => 'interval',
70 | 'resolution_time' => 'day',
71 | 'restrict_begin' => new \DateTime("-6 day"),
72 | 'restrict_end' => new \DateTime("today")
73 | ])
74 | );
75 |
76 | // Fetch productivity data grouped by activity
77 | $activities = $client->getActivities(
78 | new Params([
79 | 'perspective' => 'interval',
80 | 'resolution_time' => 'day',
81 | 'restrict_begin' => new \DateTime("-6 day"),
82 | 'restrict_end' => new \DateTime("today"),
83 | 'restrict_kind' => 'activity'
84 | ])
85 | );
86 |
87 | // Fetch productivity data grouped by category
88 | $activities = $client->getActivities(
89 | new Params([
90 | 'perspective' => 'interval',
91 | 'resolution_time' => 'day',
92 | 'restrict_begin' => new \DateTime("-6 day"),
93 | 'restrict_end' => new \DateTime("today"),
94 | 'restrict_kind' => 'category'
95 | ])
96 | );
97 |
98 | // Fetch daily productivity report data for past two weeks
99 | $daily_summary = $client->getDailySummary();
100 |
101 | foreach ($daily_summary as $day_summary) {
102 | echo $day_summary->getTotalDurationFormatted();
103 | echo $day_summary->getVeryDistractingHours();
104 | echo $day_summary->getVeryDistractingDurationFormatted();
105 | }
106 | ```
107 |
108 | You can build more complex queries and filter down the data by providing other query parameters:
109 |
110 | ``` php
111 | $client->getActivities(
112 | new Params([
113 | "perspective" => ,
114 | "resolution_time" => ,
115 | "restrict_group" => ,
116 | "restrict_user" => ,
117 | "restrict_begin" => <\DateTime>,
118 | "restrict_end" => <\DateTime>,
119 | "restrict_kind" => ,
120 | "restrict_project" => ,
121 | "restrict_thing" => ,
122 | "restrict_thingy" =>
123 | ])
124 | );
125 | ```
126 |
127 | Each query parameter is explained in more details in official [HTTP Query Interface documentation][].
128 |
129 | For a working example of an app build on top of rescuetime-api-php library take a look at [borivojevic/rescuetime-statusboard][].
130 |
131 | ### Contributing ###
132 |
133 | Patches and pull requests are welcome. Take a look at [Contributing guidelines][] for further info.
134 |
135 | ### Versioning ###
136 |
137 | The library uses [Semantic Versioning][]
138 |
139 | ### Copyright and License ###
140 |
141 | The library is licensed under the MIT license.
142 |
143 | [RescueTime]: https://www.rescuetime.com
144 | [Composer]: http://getcomposer.org/
145 | [API Key Management]: https://www.rescuetime.com/anapi/manage
146 | [HTTP Query Interface documentation]: https://www.rescuetime.com/anapi/setup/documentation#http
147 | [borivojevic/rescuetime-statusboard]: https://github.com/borivojevic/rescuetime-statusboard
148 | [Semantic Versioning]: http://semver.org/
149 | [Contributing guidelines]: https://github.com/borivojevic/rescuetime-api-php/blob/master/CONTRIBUTING.md
150 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | Vagrant.configure("2") do |config|
5 | config.vm.box = "rescuetime-0.1.0"
6 | config.vm.box_url = "https://s3.amazonaws.com/rescuetime-api-php/rescuetime.box"
7 |
8 | # Create a private network, which allows host-only access to the machine
9 | # using a specific IP.
10 | config.vm.network :private_network, ip: "192.168.33.10"
11 |
12 | # Make it so that network access from the vagrant guest is able to
13 | # use SSH private keys that are present on the host without copying
14 | # them into the VM.
15 | config.ssh.forward_agent = true
16 |
17 | # Create a public network, which generally matched to bridged network.
18 | # Bridged networks make the machine appear as another physical device on
19 | # your network.
20 | # config.vm.network :public_network
21 |
22 | # Share an additional folder to the guest VM. The first argument is
23 | # the path on the host to the actual folder. The second argument is
24 | # the path on the guest to mount the folder. And the optional third
25 | # argument is a set of non-required options.
26 | nfs_setting = RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
27 | config.vm.synced_folder ".", "/home/vagrant", id: "vagrant-root", :nfs => nfs_setting
28 |
29 | # Provider-specific configuration so you can fine-tune various
30 | # backing providers for Vagrant. These expose provider-specific options.
31 | # Example for VirtualBox:
32 | #
33 | # config.vm.provider :virtualbox do |vb|
34 | # # Don't boot with headless mode
35 | # vb.gui = true
36 | #
37 | # # Use VBoxManage to customize the VM. For example to change memory:
38 | # vb.customize ["modifyvm", :id, "--memory", "1024"]
39 | # end
40 | end
41 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "borivojevic/rescuetime",
3 | "type": "library",
4 | "description": "PHP wrapper library for RescueTime API",
5 | "keywords": ["rescuetime", "api"],
6 | "homepage": "https://github.com/borivojevic/rescuetime-api-php",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Mirko Borivojevic",
11 | "email": "mirko@mirkoborivojevic.com",
12 | "homepage": "http://mirkoborivojevic.com/"
13 | }
14 | ],
15 | "require": {
16 | "php": ">=5.4.0",
17 | "guzzle/guzzle": "3.*"
18 | },
19 | "require-dev": {
20 | "phpunit/phpunit": "3.7.*"
21 | },
22 | "autoload": {
23 | "psr-0": {
24 | "RescueTime": "src"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 | ./tests/RescueTime/
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/RescueTime/.Activity.php.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borivojevic/rescuetime-api-php/962fa1b27f72d479d8a4fdee90d48e1ca83a86be/src/RescueTime/.Activity.php.swp
--------------------------------------------------------------------------------
/src/RescueTime/Activity.php:
--------------------------------------------------------------------------------
1 | $header) {
92 | switch ($header) {
93 | case 'Rank':
94 | $properties[$key] = 'rank';
95 | break;
96 | case 'Date':
97 | $properties[$key] = 'date';
98 | break;
99 | case 'Person':
100 | $properties[$key] = 'person';
101 | break;
102 | case 'Time Spent (seconds)':
103 | $properties[$key] = 'timeSpentSeconds';
104 | break;
105 | case 'Number of People':
106 | $properties[$key] = 'numberOfPeople';
107 | break;
108 | case 'Activity':
109 | $properties[$key] = 'activityName';
110 | break;
111 | case 'Category':
112 | $properties[$key] = 'activityCategory';
113 | break;
114 | case 'Document':
115 | $properties[$key] = 'document';
116 | break;
117 | case 'Productivity':
118 | $properties[$key] = 'productivityCode';
119 | break;
120 | }
121 | }
122 |
123 | $this->rank = null;
124 | $this->date = null;
125 | $this->person = null;
126 | $this->timeSpentSeconds = null;
127 | $this->numberOfPeople = null;
128 | $this->activityName = null;
129 | $this->activityCategory = null;
130 | $this->document = null;
131 | $this->productivityCode = null;
132 |
133 | foreach ($columns as $key => $value) {
134 | if (array_key_exists($key, $properties)) {
135 | $property = $properties[$key];
136 | $this->$property = $value;
137 | }
138 | }
139 | }
140 |
141 | /**
142 | * Returns activity rank
143 | *
144 | * Present when perspective set to rank
145 | *
146 | * @return integer
147 | */
148 | public function getRank()
149 | {
150 | return $this->rank;
151 | }
152 |
153 | /**
154 | * Returns activity date
155 | *
156 | * @return string
157 | */
158 | public function getDate()
159 | {
160 | return $this->date;
161 | }
162 |
163 | /**
164 | * Returns person name
165 | *
166 | * Present when perspective set to member
167 | *
168 | * @return stirng
169 | */
170 | public function getPerson()
171 | {
172 | return $this->person;
173 | }
174 |
175 | /**
176 | * Returns time spent (seconds) on activity
177 | *
178 | * @return integer
179 | */
180 | public function getTimeSpentSeconds()
181 | {
182 | return $this->timeSpentSeconds;
183 | }
184 |
185 | /**
186 | * Returns number of people on activity
187 | *
188 | * Present when perspective set to interval or rank
189 | *
190 | * @return integer
191 | */
192 | public function getNumberOfPeople()
193 | {
194 | return $this->numberOfPeople;
195 | }
196 |
197 | /**
198 | * Returns activity name
199 | *
200 | * e.g. Program used or URL visited
201 | *
202 | * @return string
203 | */
204 | public function getActivityName()
205 | {
206 | return $this->activityName;
207 | }
208 |
209 | /**
210 | * Returns associated RescueTime activity category name
211 | *
212 | * @return string
213 | */
214 | public function getActivityCategory()
215 | {
216 | return $this->activityCategory;
217 | }
218 |
219 | /**
220 | * Returns associated RescueTime document
221 | *
222 | * @return string
223 | */
224 | public function getDocument()
225 | {
226 | return $this->document;
227 | }
228 |
229 | /**
230 | * Return RescueTime activiy productivity grade
231 | *
232 | * Integer number between -2 and 2
233 | * -2 (Very Distracting Time)
234 | * -1 (Distracting Time)
235 | * 0 (Neutral Time)
236 | * 1 (Productive Time)
237 | * 2 (Very Productive Time)
238 | *
239 | * @return integer
240 | */
241 | public function getProductivityCode()
242 | {
243 | return $this->productivityCode;
244 | }
245 |
246 | /**
247 | * Return RescueTime activiy productivity grade description
248 | *
249 | * One of very distracting, distracting, neutral, productive, very productive
250 | *
251 | * @return string
252 | */
253 | public function getProductivity()
254 | {
255 | switch ($this->productivityCode) {
256 | case -2:
257 | return "very distracting";
258 | case -1:
259 | return "distracting";
260 | case 0:
261 | return "neutral";
262 | case 1:
263 | return "productive";
264 | case 2:
265 | return "very productive";
266 | }
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/src/RescueTime/Client.php:
--------------------------------------------------------------------------------
1 |
29 | * $Client = new \RescueTime\Client($apiKey);
30 | * $activities = $Client->getActivities("rank");
31 | *
32 | *
33 | * @link https://www.rescuetime.com/analytic_api_setup/doc
34 | */
35 | class Client
36 | {
37 |
38 | /**
39 | * RescueTime API token
40 | *
41 | * @var string
42 | */
43 | private $apiKey;
44 |
45 | /**
46 | * Default HttpClient
47 | *
48 | * @var \RescueTime\HttpClient
49 | */
50 | public $httpClient;
51 |
52 | /**
53 | * Constructs RescueTime client
54 | *
55 | * @param string $apiKey RescueTime API key generated in the Embed and Data API -> Setup Data API
56 | * @link https://www.rescuetime.com/anapi/setup
57 | */
58 | public function __construct($apiKey)
59 | {
60 | $this->apiKey = $apiKey;
61 | $this->httpClient = new HttpClient($apiKey);
62 | }
63 |
64 | /**
65 | * Returns list of RescueTime activities for selected search criteria
66 | *
67 | * @param RequestQueryParameters A set of parameters to retrieve
68 | *
69 | * @return array<\RescueTime\Activity> All activities, or false if none found
70 | *
71 | * @throws \RuntimeException If API returns error
72 | * @see \RescueTime\RequestQueryParameters
73 | */
74 | public function getActivities(RequestQueryParameters $requestQueryParameters)
75 | {
76 | $responseJsonArray = $this->httpClient->request($requestQueryParameters);
77 |
78 | if (array_key_exists('error', $responseJsonArray)) {
79 | throw new \RuntimeException("API returned error: " . $responseJsonArray['error']);
80 | }
81 |
82 | $result = array();
83 | $rowHeaders = $responseJsonArray['row_headers'];
84 | foreach ($responseJsonArray['rows'] as $columns) {
85 | $result[] = new Activity($rowHeaders, $columns);
86 | }
87 |
88 | return $result ?: false;
89 | }
90 |
91 | /**
92 | * Returns list of daily summary activities
93 | *
94 | *
95 | * @return array<\RescueTime\DailyReport> All activities for previous two weeks without current day, or false if none found
96 | *
97 | * @throws \RuntimeException If API returns error
98 | * @see \RescueTime\RequestQueryParameters
99 | */
100 | public function getDailySummary()
101 | {
102 |
103 | $responseJsonArray = $this->httpClient->requestDailyReport();
104 |
105 | if (array_key_exists('error', $responseJsonArray)) {
106 | throw new \RuntimeException("API returned error: " . $responseJsonArray['error']);
107 | }
108 |
109 | $result = array();
110 | foreach ($responseJsonArray as $responseRecord) {
111 | $result[] = new DailyReport($responseRecord);
112 | }
113 |
114 | return $result ?: false;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/RescueTime/DailyReport.php:
--------------------------------------------------------------------------------
1 | $value) {
442 | $this->$property = $value;
443 | }
444 | }
445 |
446 | /**
447 | * Returns activity date
448 | *
449 | * @return string
450 | */
451 | public function getDate()
452 | {
453 | return $this->date;
454 | }
455 |
456 | /**
457 | * Returns overall productivity pulse. A scale bewteen 0-100
458 | *
459 | *
460 | * @return integer
461 | */
462 | public function getProductivityPulse()
463 | {
464 | return $this->productivity_pulse;
465 | }
466 |
467 | /**
468 | * Returns percentage representation of time spent in very productivity category
469 | *
470 | *
471 | * @return float
472 | */
473 | public function getVeryProductivePercentage()
474 | {
475 | return $this->very_productive_percentage;
476 | }
477 |
478 | /**
479 | * Returns percentage representation of time spent in productivity category
480 | *
481 | *
482 | * @return float
483 | */
484 | public function getProductivePercentage()
485 | {
486 | return $this->productive_percentage;
487 | }
488 |
489 | /**
490 | * Returns percentage representation of time spent in neutral category
491 | *
492 | *
493 | * @return float
494 | */
495 | public function getNeutralPercentage()
496 | {
497 | return $this->neutral_percentage;
498 | }
499 |
500 | /**
501 | * Returns percentage representation of time spent in distracting category
502 | *
503 | *
504 | * @return float
505 | */
506 | public function getDistractingPercentage()
507 | {
508 | return $this->distracting_percentage;
509 | }
510 |
511 | /**
512 | * Returns percentage representation of time spent in all productive categories
513 | *
514 | *
515 | * @return float
516 | */
517 | public function getAllProductivePercentage()
518 | {
519 | return $this->all_productive_percentage;
520 | }
521 |
522 | /**
523 | * Returns percentage representation of time spent in all distracting categories
524 | *
525 | *
526 | * @return float
527 | */
528 | public function getAllDistractingPercentage()
529 | {
530 | return $this->all_distracting_percentage;
531 | }
532 |
533 | /**
534 | * Returns percentage representation of time spent in all uncategorized categories
535 | *
536 | *
537 | * @return float
538 | */
539 | public function getUncategorizedPercentage()
540 | {
541 | return $this->uncategorized_percentage;
542 | }
543 |
544 | /**
545 | * Returns percentage representation of time spent in business category
546 | *
547 | *
548 | * @return float
549 | */
550 | public function getBusinessPercentage()
551 | {
552 | return $this->business_percentage;
553 | }
554 |
555 | /**
556 | * Returns percentage representation of time spent in communication and scheduling category
557 | *
558 | *
559 | * @return float
560 | */
561 | public function getCommunicationAndSchedulingPercentage()
562 | {
563 | return $this->communication_and_scheduling_percentage;
564 | }
565 |
566 | /**
567 | * Returns percentage representation of time spent in social networking category
568 | *
569 | *
570 | * @return float
571 | */
572 | public function getSocialNetworkingPercentage()
573 | {
574 | return $this->social_networking_percentage;
575 | }
576 |
577 | /**
578 | * Returns percentage representation of time spent in design and composition categories
579 | *
580 | *
581 | * @return float
582 | */
583 | public function getDesignAndCompositionPercentage()
584 | {
585 | return $this->design_and_composition_percentage;
586 | }
587 |
588 | /**
589 | * Returns percentage representation of time spent in entertainment category
590 | *
591 | *
592 | * @return float
593 | */
594 | public function getEntertainmentPercentage()
595 | {
596 | return $this->entertainment_percentage;
597 | }
598 |
599 | /**
600 | * Returns percentage representation of time spent in news category
601 | *
602 | *
603 | * @return float
604 | */
605 | public function getNewsPercentage()
606 | {
607 | return $this->news_percentage;
608 | }
609 |
610 | /**
611 | * Returns percentage representation of time spent in software development category
612 | *
613 | *
614 | * @return float
615 | */
616 | public function getSoftwareDevelopmentPercentage()
617 | {
618 | return $this->software_development_percentage;
619 | }
620 |
621 | /**
622 | * Returns percentage representation of time spent in reference and learning categories
623 | *
624 | *
625 | * @return float
626 | */
627 | public function getReferenceAndLearningPercentage()
628 | {
629 | return $this->reference_and_learning_percentage;
630 | }
631 |
632 | /**
633 | * Returns percentage representation of time spent in shopping category
634 | *
635 | *
636 | * @return float
637 | */
638 | public function getShoppingPercentage()
639 | {
640 | return $this->shopping_percentage;
641 | }
642 |
643 | /**
644 | * Returns percentage representation of time spent in shopping category
645 | *
646 | *
647 | * @return float
648 | */
649 | public function getUtilitiesPercentage()
650 | {
651 | return $this->utilities_percentage;
652 | }
653 |
654 | /**
655 | * Returns daily hours (Float with two decimal places)
656 | *
657 | *
658 | * @return float
659 | */
660 | public function getTotalHours()
661 | {
662 | return $this->total_hours;
663 | }
664 |
665 | /**
666 | * Returns hours (Float with two decimal places) representation of time spent in very productivity category
667 | *
668 | *
669 | * @return float
670 | */
671 | public function getVeryProductiveHours()
672 | {
673 | return $this->very_productive_hours;
674 | }
675 |
676 | /**
677 | * Returns hours (Float with two decimal places) representation of time spent in productivity category
678 | *
679 | *
680 | * @return float
681 | */
682 | public function getProductiveHours()
683 | {
684 | return $this->productive_hours;
685 | }
686 |
687 | /**
688 | * Returns hours (Float with two decimal places) representation of time spent in neutral category
689 | *
690 | *
691 | * @return float
692 | */
693 | public function getNeutralHours()
694 | {
695 | return $this->neutral_hours;
696 | }
697 |
698 | /**
699 | * Returns hours (Float with two decimal places) representation of time spent in distracting category
700 | *
701 | *
702 | * @return float
703 | */
704 | public function getDistractingHours()
705 | {
706 | return $this->distracting_hours;
707 | }
708 |
709 | /**
710 | * Returns hours (Float with two decimal places) representation of time spent in distracting category
711 | *
712 | *
713 | * @return float
714 | */
715 | public function getVeryDistractingHours()
716 | {
717 | return $this->very_distracting_hours;
718 | }
719 |
720 | /**
721 | * Returns hours (Float with two decimal places) representation of time spent in all productive categories
722 | *
723 | *
724 | * @return float
725 | */
726 | public function getAllProductiveHours()
727 | {
728 | return $this->all_productive_hours;
729 | }
730 |
731 | /**
732 | * Returns hours (Float with two decimal places) representation of time spent in all distracting categories
733 | *
734 | *
735 | * @return float
736 | */
737 | public function getAllDistractingHours()
738 | {
739 | return $this->all_distracting_hours;
740 | }
741 |
742 | /**
743 | * Returns hours (Float with two decimal places) representation of time spent in all uncategorized categories
744 | *
745 | *
746 | * @return float
747 | */
748 | public function getUncategorizedHours()
749 | {
750 | return $this->uncategorized_hours;
751 | }
752 |
753 | /**
754 | * Returns hours (Float with two decimal places) representation of time spent in business category
755 | *
756 | *
757 | * @return float
758 | */
759 | public function getBusinessHours()
760 | {
761 | return $this->business_hours;
762 | }
763 |
764 | /**
765 | * Returns hours (Float with two decimal places) representation of time spent in communication and scheduling category
766 | *
767 | *
768 | * @return float
769 | */
770 | public function getCommunicationAndSchedulingHours()
771 | {
772 | return $this->communication_and_scheduling_hours;
773 | }
774 |
775 | /**
776 | * Returns hours (Float with two decimal places) representation of time spent in social networking category
777 | *
778 | *
779 | * @return float
780 | */
781 | public function getSocialNetworkingHours()
782 | {
783 | return $this->social_networking_hours;
784 | }
785 |
786 | /**
787 | * Returns hours (Float with two decimal places) representation of time spent in design and composition categories
788 | *
789 | *
790 | * @return float
791 | */
792 | public function getDesignAndCompositionHours()
793 | {
794 | return $this->design_and_composition_hours;
795 | }
796 |
797 | /**
798 | * Returns hours (Float with two decimal places) representation of time spent in entertainment category
799 | *
800 | *
801 | * @return float
802 | */
803 | public function getEntertainmentHours()
804 | {
805 | return $this->entertainment_hours;
806 | }
807 |
808 | /**
809 | * Returns hours (Float with two decimal places) representation of time spent in news category
810 | *
811 | *
812 | * @return float
813 | */
814 | public function getNewsHours()
815 | {
816 | return $this->news_hours;
817 | }
818 |
819 | /**
820 | * Returns hours (Float with two decimal places) representation of time spent in software development category
821 | *
822 | *
823 | * @return float
824 | */
825 | public function getSoftwareDevelopmentHours()
826 | {
827 | return $this->software_development_hours;
828 | }
829 |
830 | /**
831 | * Returns hours (Float with two decimal places) representation of time spent in reference and learning categories
832 | *
833 | *
834 | * @return float
835 | */
836 | public function getReferenceAndLearningHours()
837 | {
838 | return $this->reference_and_learning_hours;
839 | }
840 |
841 | /**
842 | * Returns hours (Float with two decimal places) representation of time spent in shopping category
843 | *
844 | *
845 | * @return float
846 | */
847 | public function getShoppingHours()
848 | {
849 | return $this->shopping_hours;
850 | }
851 |
852 | /**
853 | * Returns hours (Float with two decimal places) representation of time spent in shopping category
854 | *
855 | *
856 | * @return float
857 | */
858 | public function getUtilitiesHours()
859 | {
860 | return $this->utilities_hours;
861 | }
862 |
863 | /**
864 | * Returns daily hours (Float with two decimal places)
865 | *
866 | *
867 | * @return string
868 | */
869 | public function getTotalDurationFormatted()
870 | {
871 | return $this->total_duration_formatted;
872 | }
873 |
874 | /**
875 | * Returns hours (Float with two decimal places) representation of time spent in very productivity category
876 | *
877 | *
878 | * @return string
879 | */
880 | public function getVeryProductiveDurationFormatted()
881 | {
882 | return $this->very_productive_duration_formatted;
883 | }
884 |
885 | /**
886 | * Returns hours (Float with two decimal places) representation of time spent in productivity category
887 | *
888 | *
889 | * @return string
890 | */
891 | public function getProductiveDurationFormatted()
892 | {
893 | return $this->productive_duration_formatted;
894 | }
895 |
896 | /**
897 | * Returns hours (Float with two decimal places) representation of time spent in neutral category
898 | *
899 | *
900 | * @return string
901 | */
902 | public function getNeutralDurationFormatted()
903 | {
904 | return $this->neutral_duration_formatted;
905 | }
906 |
907 | /**
908 | * Returns hours (Float with two decimal places) representation of time spent in distracting category
909 | *
910 | *
911 | * @return string
912 | */
913 | public function getDistractingDurationFormatted()
914 | {
915 | return $this->distracting_duration_formatted;
916 | }
917 |
918 | /**
919 | * Returns hours (Float with two decimal places) representation of time spent in distracting category
920 | *
921 | *
922 | * @return string
923 | */
924 | public function getVeryDistractingDurationFormatted()
925 | {
926 | return $this->very_distracting_duration_formatted;
927 | }
928 |
929 | /**
930 | * Returns hours (Float with two decimal places) representation of time spent in all productive categories
931 | *
932 | *
933 | * @return string
934 | */
935 | public function getAllProductiveDurationFormatted()
936 | {
937 | return $this->all_productive_duration_formatted;
938 | }
939 |
940 | /**
941 | * Returns hours (Float with two decimal places) representation of time spent in all distracting categories
942 | *
943 | *
944 | * @return string
945 | */
946 | public function getAllDistractingDurationFormatted()
947 | {
948 | return $this->all_distracting_duration_formatted;
949 | }
950 |
951 | /**
952 | * Returns hours (Float with two decimal places) representation of time spent in all uncategorized categories
953 | *
954 | *
955 | * @return string
956 | */
957 | public function getUncategorizedDurationFormatted()
958 | {
959 | return $this->uncategorized_duration_formatted;
960 | }
961 |
962 | /**
963 | * Returns hours (Float with two decimal places) representation of time spent in business category
964 | *
965 | *
966 | * @return string
967 | */
968 | public function getBusinessDurationFormatted()
969 | {
970 | return $this->business_duration_formatted;
971 | }
972 |
973 | /**
974 | * Returns hours (Float with two decimal places) representation of time spent in communication and scheduling category
975 | *
976 | *
977 | * @return string
978 | */
979 | public function getCommunicationAndSchedulingDurationFormatted()
980 | {
981 | return $this->communication_and_scheduling_duration_formatted;
982 | }
983 |
984 | /**
985 | * Returns hours (Float with two decimal places) representation of time spent in social networking category
986 | *
987 | *
988 | * @return string
989 | */
990 | public function getSocialNetworkingDurationFormatted()
991 | {
992 | return $this->social_networking_duration_formatted;
993 | }
994 |
995 | /**
996 | * Returns hours (Float with two decimal places) representation of time spent in design and composition categories
997 | *
998 | *
999 | * @return string
1000 | */
1001 | public function getDesignAndCompositionDurationFormatted()
1002 | {
1003 | return $this->design_and_composition_duration_formatted;
1004 | }
1005 |
1006 | /**
1007 | * Returns hours (Float with two decimal places) representation of time spent in entertainment category
1008 | *
1009 | *
1010 | * @return string
1011 | */
1012 | public function getEntertainmentDurationFormatted()
1013 | {
1014 | return $this->entertainment_duration_formatted;
1015 | }
1016 |
1017 | /**
1018 | * Returns hours (Float with two decimal places) representation of time spent in news category
1019 | *
1020 | *
1021 | * @return string
1022 | */
1023 | public function getNewsDurationFormatted()
1024 | {
1025 | return $this->news_duration_formatted;
1026 | }
1027 |
1028 | /**
1029 | * Returns hours (Float with two decimal places) representation of time spent in software development category
1030 | *
1031 | *
1032 | * @return string
1033 | */
1034 | public function getSoftwareDevelopmentDurationFormatted()
1035 | {
1036 | return $this->software_development_duration_formatted;
1037 | }
1038 |
1039 | /**
1040 | * Returns hours (Float with two decimal places) representation of time spent in reference and learning categories
1041 | *
1042 | *
1043 | * @return string
1044 | */
1045 | public function getReferenceAndLearningDurationFormatted()
1046 | {
1047 | return $this->reference_and_learning_duration_formatted;
1048 | }
1049 |
1050 | /**
1051 | * Returns hours (Float with two decimal places) representation of time spent in shopping category
1052 | *
1053 | *
1054 | * @return string
1055 | */
1056 | public function getShoppingDurationFormatted()
1057 | {
1058 | return $this->shopping_duration_formatted;
1059 | }
1060 |
1061 | /**
1062 | * Returns hours (Float with two decimal places) representation of time spent in shopping category
1063 | *
1064 | *
1065 | * @return string
1066 | */
1067 | public function getUtilitiesDurationFormatted()
1068 | {
1069 | return $this->utilities_duration_formatted;
1070 | }
1071 | }
1072 |
--------------------------------------------------------------------------------
/src/RescueTime/HttpClient.php:
--------------------------------------------------------------------------------
1 | apiKey = $apiKey;
50 | $this->apiEndpoint = 'https://www.rescuetime.com';
51 | $this->format = 'json';
52 | $this->guzzleClient = null;
53 | }
54 |
55 | /**
56 | * Sends request to RescueTime API
57 | *
58 | * @return array Decoded json returned by server
59 | */
60 | public function request(RequestQueryParameters $params)
61 | {
62 | $client = $this->guzzleClient ?: new GuzzleClient($this->apiEndpoint);
63 |
64 | $request = $client->get(
65 | '/anapi/data',
66 | ['Accept' => 'application/json'],
67 | ['query' => ['key' => $this->apiKey, 'format' => $this->format] + $params->toArray()]
68 | );
69 |
70 | $response = $request->send();
71 |
72 | return $this->handleResponse($response);
73 | }
74 |
75 | /**
76 | * Sends Daily Report request to RescueTime API
77 | *
78 | * @return array Decoded json returned by server
79 | */
80 | public function requestDailyReport()
81 | {
82 | $client = $this->guzzleClient ?: new GuzzleClient($this->apiEndpoint);
83 |
84 | $request = $client->get(
85 | '/anapi/daily_summary_feed',
86 | ['Accept' => 'application/json'],
87 | ['query' => ['key' => $this->apiKey, 'format' => $this->format]]
88 | );
89 |
90 | $response = $request->send();
91 |
92 | return $this->handleResponse($response);
93 | }
94 |
95 | /**
96 | * Parses RescueTime API response and handles HTTP/API errors
97 | * @param String $response Raw API response
98 | * @return array Decoded json returned by server
99 | * @throws \Exception If API server can not be contacted or returns an error
100 | */
101 | private function handleResponse($response)
102 | {
103 | if (!$response || !$response->isSuccessful()) {
104 | throw new \Exception("HTTP request failed");
105 | }
106 |
107 | if ($response->getInfo("size_download") == 0) {
108 | throw new \Exception("HTTP body empty");
109 | }
110 |
111 | try {
112 | $responseJsonArray = json_decode($response->getBody(), true);
113 | } catch (RuntimeException $e) {
114 | throw new \Exception("Invalid JSON response: " . $e->getMessage());
115 | }
116 |
117 | return $responseJsonArray;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/RescueTime/RequestQueryParameters.php:
--------------------------------------------------------------------------------
1 | null,
181 | 'version' => null,
182 | 'perspective' => 'rank',
183 | 'resolution_time' => 'hour',
184 | 'restrict_group' => null,
185 | 'restrict_user' => null,
186 | 'restrict_begin' => null,
187 | 'restrict_end' => null,
188 | 'restrict_kind' => null,
189 | 'restrict_project' => null,
190 | 'restrict_thing' => null,
191 | 'restrict_thingy' => null,
192 | ];
193 |
194 | /**
195 | * Constructs RequestQueryParameters class
196 | *
197 | * Available options to specify in the params argument:
198 | *
199 | * string perspective One of "rank", "interval", "member"
200 | * string resolution_time One of "month", "week", "day", "hour"
201 | * string restrict_group One group name
202 | * string restrict_user One user name or user email
203 | * \DateTime restrict_begin Sets the start day for data batch
204 | * \DateTime restrict_end Sets the end day for data batch
205 | * string restrict_kind One of "category", "activity", "productivity", "document"
206 | * string restrict_project Name of project
207 | * string restrict_thing Name of category, activity, or overview
208 | * string restrict_thingy Name of specific "document" or "activity"
209 | *
210 | * @param array $params
211 | */
212 | public function __construct(array $params)
213 | {
214 | $params = $params + $this->defaultParams;
215 | $this->operation = 'select';
216 | $this->version = 0;
217 | $this->setPerspective($params['perspective']);
218 | $this->setResolutionTime($params['resolution_time']);
219 | $this->restrict_group = $params['restrict_group'];
220 | $this->restrict_user = $params['restrict_user'];
221 | $this->restrict_begin = $params['restrict_begin'];
222 | $this->restrict_end = $params['restrict_end'];
223 | $this->setRestrictKind($params['restrict_kind']);
224 | $this->restrict_project = $params['restrict_project'];
225 | $this->restrict_thing = $params['restrict_thing'];
226 | $this->restrict_thingy = $params['restrict_thingy'];
227 | }
228 |
229 | /**
230 | * Class properties accessor
231 | *
232 | * Utilized for reading data from inaccessible properties
233 | *
234 | * @param string $attribute Property name
235 | *
236 | * @return mixed Property value
237 | */
238 | public function __get($attribute)
239 | {
240 | if (property_exists($this, $attribute)) {
241 | return $this->$attribute;
242 | }
243 |
244 | return null;
245 | }
246 |
247 | /**
248 | * Sets perspective property
249 | * Please refer to @availablePerspectives for available options
250 | *
251 | * @param string $perspective
252 | * @throws \InvalidArgumentException If perspective not in available perspectives
253 | */
254 | public function setPerspective($perspective)
255 | {
256 | if ($perspective && !in_array($perspective, $this->availablePerspectives)) {
257 | throw new \InvalidArgumentException(
258 | sprintf("Perspective must be one of %s", implode(', ', $this->availablePerspectives))
259 | );
260 | }
261 | $this->perspective = $perspective;
262 | }
263 |
264 | /**
265 | * Sets resolution property
266 | * Please refer to @availableResolutionTimes for available options
267 | *
268 | * @param string $resolution
269 | * @throws \InvalidArgumentException If resolution not in available resolution times
270 | */
271 | public function setResolutionTime($resolution)
272 | {
273 | if ($resolution && !in_array($resolution, $this->availableResolutionTimes)) {
274 | throw new \InvalidArgumentException(
275 | sprintf("Resolution time must be one of %s", implode(', ', $this->availableResolutionTimes))
276 | );
277 | }
278 | $this->resolution_time = $resolution;
279 | }
280 |
281 | /**
282 | * Sets resetrict_kind property
283 | * Please refer to @availableRestrictKinds for available options
284 | *
285 | * @param string $kind
286 | * @throws \InvalidArgumentException If property not in available restrict kinds
287 | */
288 | public function setRestrictKind($kind)
289 | {
290 | if ($kind && !in_array($kind, $this->availableRestrictKinds)) {
291 | throw new \InvalidArgumentException(
292 | sprintf("Restrict kind must be one of %s", implode(', ', $this->availableRestrictKinds))
293 | );
294 | }
295 | $this->restrict_kind = $kind;
296 | }
297 |
298 | /**
299 | * Serializes query parameters array to API endpoint specific format
300 | *
301 | * @return array
302 | */
303 | public function toArray()
304 | {
305 | $queryParams = array(
306 | 'operation' => $this->operation,
307 | 'version' => $this->version,
308 | 'perspective' => $this->perspective,
309 | 'resolution_time' => $this->resolution_time,
310 | 'restrict_group' => $this->restrict_group,
311 | 'restrict_user' => $this->restrict_user,
312 | 'restrict_kind' => $this->restrict_kind,
313 | 'restrict_project' => $this->restrict_project,
314 | 'restrict_thing' => $this->restrict_thing,
315 | 'restrict_thingy' => $this->restrict_thingy
316 | );
317 | if ($this->restrict_begin) {
318 | $queryParams['restrict_begin'] = $this->restrict_begin->format('Y-m-d');
319 | }
320 | if ($this->restrict_end) {
321 | $queryParams['restrict_end'] = $this->restrict_end->format('Y-m-d');
322 | }
323 |
324 | return array_filter($queryParams);
325 | }
326 | }
327 |
--------------------------------------------------------------------------------
/tests/RescueTime/Tests/ClientTest.php:
--------------------------------------------------------------------------------
1 | Client = new \RescueTime\Client($apiKey);
18 | }
19 |
20 | /**
21 | * tearDown method
22 | *
23 | * @return void
24 | */
25 | public function tearDown()
26 | {
27 | parent::tearDown();
28 | unset($this->Client);
29 | }
30 |
31 | public function testGetByRank()
32 | {
33 | $data = file_get_contents(__DIR__ . '/Fakes/rank.json');
34 |
35 | $requestParams = array('perspective' => 'rank');
36 |
37 | $httpClient = $this->getMockBuilder('\RescueTime\HttpClient')
38 | ->setConstructorArgs(array($requestParams))
39 | ->setMethods(array('request'))
40 | ->getMock();
41 | $httpClient->expects($this->once())
42 | ->method('request')
43 | ->will($this->returnValue(json_decode($data, true)));
44 |
45 | $this->Client->httpClient = $httpClient;
46 |
47 | $activities = $this->Client->getActivities(new Params($requestParams));
48 |
49 | $this->assertTrue(is_array($activities), "Expected activities to be an array");
50 | $this->assertEquals(15, count($activities), "Expected to return 15 activities");
51 | }
52 |
53 | public function testGetByInterval()
54 | {
55 | $data = file_get_contents(__DIR__ . '/Fakes/interval.json');
56 |
57 | $requestParams = array('perspective' => 'interval');
58 |
59 | $httpClient = $this->getMockBuilder('\RescueTime\HttpClient')
60 | ->setConstructorArgs(array($requestParams))
61 | ->setMethods(array('request'))
62 | ->getMock();
63 | $httpClient->expects($this->once())
64 | ->method('request')
65 | ->will($this->returnValue(json_decode($data, true)));
66 |
67 | $this->Client->httpClient = $httpClient;
68 |
69 | $activities = $this->Client->getActivities(new Params($requestParams));
70 |
71 | $this->assertTrue(is_array($activities), "Expected activities to be an array");
72 | $this->assertEquals(14, count($activities), "Expected to return 14 activities");
73 | }
74 |
75 | public function testGetByMember()
76 | {
77 | $data = file_get_contents(__DIR__ . '/Fakes/member.json');
78 |
79 | $requestParams = array('perspective' => 'member');
80 |
81 | $httpClient = $this->getMockBuilder('\RescueTime\HttpClient')
82 | ->setConstructorArgs(array($requestParams))
83 | ->setMethods(array('request'))
84 | ->getMock();
85 | $httpClient->expects($this->once())
86 | ->method('request')
87 | ->will($this->returnValue(json_decode($data, true)));
88 |
89 | $this->Client->httpClient = $httpClient;
90 |
91 | $activities = $this->Client->getActivities(new Params($requestParams));
92 |
93 | $this->assertTrue(is_array($activities), "Expected activities to be an array");
94 | $this->assertEquals(17, count($activities), "Expected to return 17 activities");
95 | }
96 |
97 | public function testGetDailyReport()
98 | {
99 | $data = file_get_contents(__DIR__ . '/Fakes/daily_report.json');
100 | $requestParams = array();
101 |
102 | $httpClient = $this->getMockBuilder('\RescueTime\HttpClient')
103 | ->setConstructorArgs(array($requestParams))
104 | ->setMethods(array('requestDailyReport'))
105 | ->getMock();
106 | $httpClient->expects($this->once())
107 | ->method('requestDailyReport')
108 | ->will($this->returnValue(json_decode($data, true)));
109 |
110 | $this->Client->httpClient = $httpClient;
111 |
112 | $report = $this->Client->getDailySummary();
113 |
114 | $this->assertTrue(is_array($report), "Expected activities to be an array");
115 | $this->assertEquals(15, count($report), "Expected to return 15 activities");
116 | }
117 |
118 | /**
119 | * @expectedException InvalidArgumentException
120 | * @expectedExceptionMessage Perspective must be one of rank, interval, member
121 | */
122 | public function testInvalidPerspective()
123 | {
124 | $this->Client->getActivities(new Params(['perspective' => 'invalid_perspective_name']));
125 | }
126 |
127 | /**
128 | * @expectedException InvalidArgumentException
129 | * @expectedExceptionMessage Resolution time must be one of month, week, day, hour
130 | */
131 | public function testInvalidResolutionTime()
132 | {
133 | $this->Client->getActivities(new Params(['resolution_time' => 'invalid_resolution_time']));
134 | }
135 |
136 | /**
137 | * @expectedException InvalidArgumentException
138 | * @expectedExceptionMessage Restrict kind must be one of category, activity, productivity
139 | */
140 | public function testInvalidRestrictKind()
141 | {
142 | $this->Client->getActivities(new Params(['restrict_kind' => 'invalid_restrict_kind']));
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/tests/RescueTime/Tests/Fakes/daily_report.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id":1465369200,
4 | "date":"2016-06-08",
5 | "productivity_pulse":65,
6 | "very_productive_percentage":46.8,
7 | "productive_percentage":5.9,
8 | "neutral_percentage":22.6,
9 | "distracting_percentage":10.5,
10 | "very_distracting_percentage":14.1,
11 | "all_productive_percentage":52.7,
12 | "all_distracting_percentage":24.6,
13 | "uncategorized_percentage":7.7,
14 | "business_percentage":5.2,
15 | "communication_and_scheduling_percentage":14.6,
16 | "social_networking_percentage":11.5,
17 | "design_and_composition_percentage":7.6,
18 | "entertainment_percentage":1,
19 | "news_percentage":2.4,
20 | "software_development_percentage":34,
21 | "reference_and_learning_percentage":3.6,
22 | "shopping_percentage":0.1,
23 | "utilities_percentage":12.4,
24 | "total_hours":12.22,
25 | "very_productive_hours":5.72,
26 | "productive_hours":0.73,
27 | "neutral_hours":2.76,
28 | "distracting_hours":1.28,
29 | "very_distracting_hours":1.73,
30 | "all_productive_hours":6.44,
31 | "all_distracting_hours":3.01,
32 | "uncategorized_hours":0.94,
33 | "business_hours":0.64,
34 | "communication_and_scheduling_hours":1.78,
35 | "social_networking_hours":1.4,
36 | "design_and_composition_hours":0.92,
37 | "entertainment_hours":0.13,
38 | "news_hours":0.29,
39 | "software_development_hours":4.15,
40 | "reference_and_learning_hours":0.44,
41 | "shopping_hours":0.01,
42 | "utilities_hours":1.51,
43 | "total_duration_formatted":"12h 12m",
44 | "very_productive_duration_formatted":"5h 43m",
45 | "productive_duration_formatted":"43m 30s",
46 | "neutral_duration_formatted":"2h 45m",
47 | "distracting_duration_formatted":"1h 17m",
48 | "very_distracting_duration_formatted":"1h 43m",
49 | "all_productive_duration_formatted":"6h 26m",
50 | "all_distracting_duration_formatted":"3h",
51 | "uncategorized_duration_formatted":"56m 7s",
52 | "business_duration_formatted":"38m 28s",
53 | "communication_and_scheduling_duration_formatted":"1h 46m",
54 | "social_networking_duration_formatted":"1h 24m",
55 | "design_and_composition_duration_formatted":"55m 22s",
56 | "entertainment_duration_formatted":"7m 32s",
57 | "news_duration_formatted":"17m 29s",
58 | "software_development_duration_formatted":"4h 9m",
59 | "reference_and_learning_duration_formatted":"26m 39s",
60 | "shopping_duration_formatted":"41s",
61 | "utilities_duration_formatted":"1h 30m"
62 | },
63 | {
64 | "id":1465282800,
65 | "date":"2016-06-07",
66 | "productivity_pulse":65,
67 | "very_productive_percentage":48.3,
68 | "productive_percentage":5.1,
69 | "neutral_percentage":18.2,
70 | "distracting_percentage":16.4,
71 | "very_distracting_percentage":12,
72 | "all_productive_percentage":53.4,
73 | "all_distracting_percentage":28.4,
74 | "uncategorized_percentage":11.9,
75 | "business_percentage":5.6,
76 | "communication_and_scheduling_percentage":16.4,
77 | "social_networking_percentage":7.9,
78 | "design_and_composition_percentage":0.7,
79 | "entertainment_percentage":1.6,
80 | "news_percentage":5.2,
81 | "software_development_percentage":42,
82 | "reference_and_learning_percentage":3.9,
83 | "shopping_percentage":0.3,
84 | "utilities_percentage":4.4,
85 | "total_hours":10.56,
86 | "very_productive_hours":5.1,
87 | "productive_hours":0.54,
88 | "neutral_hours":1.93,
89 | "distracting_hours":1.73,
90 | "very_distracting_hours":1.27,
91 | "all_productive_hours":5.64,
92 | "all_distracting_hours":3,
93 | "uncategorized_hours":1.26,
94 | "business_hours":0.59,
95 | "communication_and_scheduling_hours":1.73,
96 | "social_networking_hours":0.84,
97 | "design_and_composition_hours":0.07,
98 | "entertainment_hours":0.17,
99 | "news_hours":0.55,
100 | "software_development_hours":4.43,
101 | "reference_and_learning_hours":0.41,
102 | "shopping_hours":0.03,
103 | "utilities_hours":0.47,
104 | "total_duration_formatted":"10h 33m",
105 | "very_productive_duration_formatted":"5h 5m",
106 | "productive_duration_formatted":"32m 14s",
107 | "neutral_duration_formatted":"1h 55m",
108 | "distracting_duration_formatted":"1h 43m",
109 | "very_distracting_duration_formatted":"1h 16m",
110 | "all_productive_duration_formatted":"5h 38m",
111 | "all_distracting_duration_formatted":"2h 59m",
112 | "uncategorized_duration_formatted":"1h 15m",
113 | "business_duration_formatted":"35m 38s",
114 | "communication_and_scheduling_duration_formatted":"1h 43m",
115 | "social_networking_duration_formatted":"50m 18s",
116 | "design_and_composition_duration_formatted":"4m 18s",
117 | "entertainment_duration_formatted":"10m 12s",
118 | "news_duration_formatted":"33m 9s",
119 | "software_development_duration_formatted":"4h 26m",
120 | "reference_and_learning_duration_formatted":"24m 48s",
121 | "shopping_duration_formatted":"1m 50s",
122 | "utilities_duration_formatted":"27m 55s"
123 | },
124 | {
125 | "id":1465196400,
126 | "date":"2016-06-06",
127 | "productivity_pulse":64,
128 | "very_productive_percentage":48.6,
129 | "productive_percentage":6.7,
130 | "neutral_percentage":13.9,
131 | "distracting_percentage":16,
132 | "very_distracting_percentage":14.8,
133 | "all_productive_percentage":55.3,
134 | "all_distracting_percentage":30.7,
135 | "uncategorized_percentage":6.9,
136 | "business_percentage":15,
137 | "communication_and_scheduling_percentage":20.6,
138 | "social_networking_percentage":10.4,
139 | "design_and_composition_percentage":1.6,
140 | "entertainment_percentage":1.3,
141 | "news_percentage":4.1,
142 | "software_development_percentage":32,
143 | "reference_and_learning_percentage":3.1,
144 | "shopping_percentage":0,
145 | "utilities_percentage":4.9,
146 | "total_hours":11.53,
147 | "very_productive_hours":5.61,
148 | "productive_hours":0.77,
149 | "neutral_hours":1.61,
150 | "distracting_hours":1.84,
151 | "very_distracting_hours":1.7,
152 | "all_productive_hours":6.38,
153 | "all_distracting_hours":3.55,
154 | "uncategorized_hours":0.8,
155 | "business_hours":1.73,
156 | "communication_and_scheduling_hours":2.37,
157 | "social_networking_hours":1.2,
158 | "design_and_composition_hours":0.18,
159 | "entertainment_hours":0.15,
160 | "news_hours":0.48,
161 | "software_development_hours":3.69,
162 | "reference_and_learning_hours":0.35,
163 | "shopping_hours":0,
164 | "utilities_hours":0.56,
165 | "total_duration_formatted":"11h 32m",
166 | "very_productive_duration_formatted":"5h 36m",
167 | "productive_duration_formatted":"46m 23s",
168 | "neutral_duration_formatted":"1h 36m",
169 | "distracting_duration_formatted":"1h 50m",
170 | "very_distracting_duration_formatted":"1h 42m",
171 | "all_productive_duration_formatted":"6h 22m",
172 | "all_distracting_duration_formatted":"3h 32m",
173 | "uncategorized_duration_formatted":"48m 3s",
174 | "business_duration_formatted":"1h 43m",
175 | "communication_and_scheduling_duration_formatted":"2h 22m",
176 | "social_networking_duration_formatted":"1h 12m",
177 | "design_and_composition_duration_formatted":"11m 4s",
178 | "entertainment_duration_formatted":"9m 16s",
179 | "news_duration_formatted":"28m 39s",
180 | "software_development_duration_formatted":"3h 41m",
181 | "reference_and_learning_duration_formatted":"21m 11s",
182 | "shopping_duration_formatted":"10s",
183 | "utilities_duration_formatted":"33m 37s"
184 | },
185 | {
186 | "id":1465110000,
187 | "date":"2016-06-05",
188 | "productivity_pulse":39,
189 | "very_productive_percentage":21.6,
190 | "productive_percentage":10.1,
191 | "neutral_percentage":17.7,
192 | "distracting_percentage":6.9,
193 | "very_distracting_percentage":43.8,
194 | "all_productive_percentage":31.7,
195 | "all_distracting_percentage":50.6,
196 | "uncategorized_percentage":13.4,
197 | "business_percentage":0.3,
198 | "communication_and_scheduling_percentage":4.6,
199 | "social_networking_percentage":27.8,
200 | "design_and_composition_percentage":12.3,
201 | "entertainment_percentage":6.5,
202 | "news_percentage":11.2,
203 | "software_development_percentage":8.9,
204 | "reference_and_learning_percentage":7.9,
205 | "shopping_percentage":0.1,
206 | "utilities_percentage":6.9,
207 | "total_hours":6.36,
208 | "very_productive_hours":1.37,
209 | "productive_hours":0.64,
210 | "neutral_hours":1.13,
211 | "distracting_hours":0.44,
212 | "very_distracting_hours":2.79,
213 | "all_productive_hours":2.02,
214 | "all_distracting_hours":3.22,
215 | "uncategorized_hours":0.85,
216 | "business_hours":0.02,
217 | "communication_and_scheduling_hours":0.29,
218 | "social_networking_hours":1.77,
219 | "design_and_composition_hours":0.78,
220 | "entertainment_hours":0.41,
221 | "news_hours":0.71,
222 | "software_development_hours":0.57,
223 | "reference_and_learning_hours":0.5,
224 | "shopping_hours":0.01,
225 | "utilities_hours":0.44,
226 | "total_duration_formatted":"6h 21m",
227 | "very_productive_duration_formatted":"1h 22m",
228 | "productive_duration_formatted":"38m 33s",
229 | "neutral_duration_formatted":"1h 7m",
230 | "distracting_duration_formatted":"26m 14s",
231 | "very_distracting_duration_formatted":"2h 47m",
232 | "all_productive_duration_formatted":"2h",
233 | "all_distracting_duration_formatted":"3h 13m",
234 | "uncategorized_duration_formatted":"51m 6s",
235 | "business_duration_formatted":"1m 15s",
236 | "communication_and_scheduling_duration_formatted":"17m 27s",
237 | "social_networking_duration_formatted":"1h 46m",
238 | "design_and_composition_duration_formatted":"47m",
239 | "entertainment_duration_formatted":"24m 53s",
240 | "news_duration_formatted":"42m 42s",
241 | "software_development_duration_formatted":"34m 6s",
242 | "reference_and_learning_duration_formatted":"30m 17s",
243 | "shopping_duration_formatted":"20s",
244 | "utilities_duration_formatted":"26m 27s"
245 | },
246 | {
247 | "id":1465023600,
248 | "date":"2016-06-04",
249 | "productivity_pulse":42,
250 | "very_productive_percentage":25.7,
251 | "productive_percentage":11.1,
252 | "neutral_percentage":14.9,
253 | "distracting_percentage":2.2,
254 | "very_distracting_percentage":46,
255 | "all_productive_percentage":36.9,
256 | "all_distracting_percentage":48.2,
257 | "uncategorized_percentage":9.6,
258 | "business_percentage":0.9,
259 | "communication_and_scheduling_percentage":4.7,
260 | "social_networking_percentage":32.7,
261 | "design_and_composition_percentage":22.7,
262 | "entertainment_percentage":5.6,
263 | "news_percentage":4.8,
264 | "software_development_percentage":2.1,
265 | "reference_and_learning_percentage":4.8,
266 | "shopping_percentage":0.9,
267 | "utilities_percentage":11.1,
268 | "total_hours":7.02,
269 | "very_productive_hours":1.81,
270 | "productive_hours":0.78,
271 | "neutral_hours":1.05,
272 | "distracting_hours":0.15,
273 | "very_distracting_hours":3.23,
274 | "all_productive_hours":2.59,
275 | "all_distracting_hours":3.38,
276 | "uncategorized_hours":0.68,
277 | "business_hours":0.06,
278 | "communication_and_scheduling_hours":0.33,
279 | "social_networking_hours":2.3,
280 | "design_and_composition_hours":1.6,
281 | "entertainment_hours":0.4,
282 | "news_hours":0.34,
283 | "software_development_hours":0.15,
284 | "reference_and_learning_hours":0.34,
285 | "shopping_hours":0.06,
286 | "utilities_hours":0.78,
287 | "total_duration_formatted":"7h 1m",
288 | "very_productive_duration_formatted":"1h 48m",
289 | "productive_duration_formatted":"46m 58s",
290 | "neutral_duration_formatted":"1h 2m",
291 | "distracting_duration_formatted":"9m 9s",
292 | "very_distracting_duration_formatted":"3h 13m",
293 | "all_productive_duration_formatted":"2h 35m",
294 | "all_distracting_duration_formatted":"3h 23m",
295 | "uncategorized_duration_formatted":"40m 31s",
296 | "business_duration_formatted":"3m 42s",
297 | "communication_and_scheduling_duration_formatted":"19m 50s",
298 | "social_networking_duration_formatted":"2h 17m",
299 | "design_and_composition_duration_formatted":"1h 35m",
300 | "entertainment_duration_formatted":"23m 44s",
301 | "news_duration_formatted":"20m 15s",
302 | "software_development_duration_formatted":"8m 55s",
303 | "reference_and_learning_duration_formatted":"20m 22s",
304 | "shopping_duration_formatted":"3m 37s",
305 | "utilities_duration_formatted":"46m 50s"
306 | },
307 | {
308 | "id":1464937200,
309 | "date":"2016-06-03",
310 | "productivity_pulse":57,
311 | "very_productive_percentage":37.2,
312 | "productive_percentage":11.9,
313 | "neutral_percentage":10.2,
314 | "distracting_percentage":23.2,
315 | "very_distracting_percentage":17.4,
316 | "all_productive_percentage":49.1,
317 | "all_distracting_percentage":40.7,
318 | "uncategorized_percentage":4.1,
319 | "business_percentage":15.7,
320 | "communication_and_scheduling_percentage":24,
321 | "social_networking_percentage":16,
322 | "design_and_composition_percentage":4.7,
323 | "entertainment_percentage":0.7,
324 | "news_percentage":3.7,
325 | "software_development_percentage":16.8,
326 | "reference_and_learning_percentage":9.8,
327 | "shopping_percentage":0,
328 | "utilities_percentage":4.4,
329 | "total_hours":10.12,
330 | "very_productive_hours":3.77,
331 | "productive_hours":1.2,
332 | "neutral_hours":1.03,
333 | "distracting_hours":2.35,
334 | "very_distracting_hours":1.77,
335 | "all_productive_hours":4.97,
336 | "all_distracting_hours":4.12,
337 | "uncategorized_hours":0.42,
338 | "business_hours":1.59,
339 | "communication_and_scheduling_hours":2.43,
340 | "social_networking_hours":1.62,
341 | "design_and_composition_hours":0.47,
342 | "entertainment_hours":0.07,
343 | "news_hours":0.38,
344 | "software_development_hours":1.7,
345 | "reference_and_learning_hours":0.99,
346 | "shopping_hours":0,
347 | "utilities_hours":0.44,
348 | "total_duration_formatted":"10h 7m",
349 | "very_productive_duration_formatted":"3h 46m",
350 | "productive_duration_formatted":"1h 12m",
351 | "neutral_duration_formatted":"1h 1m",
352 | "distracting_duration_formatted":"2h 21m",
353 | "very_distracting_duration_formatted":"1h 45m",
354 | "all_productive_duration_formatted":"4h 58m",
355 | "all_distracting_duration_formatted":"4h 6m",
356 | "uncategorized_duration_formatted":"24m 59s",
357 | "business_duration_formatted":"1h 35m",
358 | "communication_and_scheduling_duration_formatted":"2h 25m",
359 | "social_networking_duration_formatted":"1h 37m",
360 | "design_and_composition_duration_formatted":"28m 16s",
361 | "entertainment_duration_formatted":"4m 20s",
362 | "news_duration_formatted":"22m 45s",
363 | "software_development_duration_formatted":"1h 42m",
364 | "reference_and_learning_duration_formatted":"59m 19s",
365 | "shopping_duration_formatted":"11s",
366 | "utilities_duration_formatted":"26m 30s"
367 | },
368 | {
369 | "id":1464850800,
370 | "date":"2016-06-02",
371 | "productivity_pulse":48,
372 | "very_productive_percentage":25.7,
373 | "productive_percentage":7.6,
374 | "neutral_percentage":25.3,
375 | "distracting_percentage":18.7,
376 | "very_distracting_percentage":22.7,
377 | "all_productive_percentage":33.3,
378 | "all_distracting_percentage":41.5,
379 | "uncategorized_percentage":13,
380 | "business_percentage":10.8,
381 | "communication_and_scheduling_percentage":24.7,
382 | "social_networking_percentage":17.2,
383 | "design_and_composition_percentage":2.4,
384 | "entertainment_percentage":3.3,
385 | "news_percentage":2.1,
386 | "software_development_percentage":12.5,
387 | "reference_and_learning_percentage":4.6,
388 | "shopping_percentage":0.4,
389 | "utilities_percentage":9,
390 | "total_hours":11.38,
391 | "very_productive_hours":2.92,
392 | "productive_hours":0.87,
393 | "neutral_hours":2.88,
394 | "distracting_hours":2.13,
395 | "very_distracting_hours":2.59,
396 | "all_productive_hours":3.78,
397 | "all_distracting_hours":4.72,
398 | "uncategorized_hours":1.48,
399 | "business_hours":1.23,
400 | "communication_and_scheduling_hours":2.82,
401 | "social_networking_hours":1.96,
402 | "design_and_composition_hours":0.27,
403 | "entertainment_hours":0.38,
404 | "news_hours":0.24,
405 | "software_development_hours":1.42,
406 | "reference_and_learning_hours":0.52,
407 | "shopping_hours":0.05,
408 | "utilities_hours":1.02,
409 | "total_duration_formatted":"11h 22m",
410 | "very_productive_duration_formatted":"2h 55m",
411 | "productive_duration_formatted":"51m 56s",
412 | "neutral_duration_formatted":"2h 52m",
413 | "distracting_duration_formatted":"2h 8m",
414 | "very_distracting_duration_formatted":"2h 35m",
415 | "all_productive_duration_formatted":"3h 47m",
416 | "all_distracting_duration_formatted":"4h 43m",
417 | "uncategorized_duration_formatted":"1h 28m",
418 | "business_duration_formatted":"1h 13m",
419 | "communication_and_scheduling_duration_formatted":"2h 48m",
420 | "social_networking_duration_formatted":"1h 57m",
421 | "design_and_composition_duration_formatted":"16m 14s",
422 | "entertainment_duration_formatted":"22m 33s",
423 | "news_duration_formatted":"14m 34s",
424 | "software_development_duration_formatted":"1h 25m",
425 | "reference_and_learning_duration_formatted":"31m 11s",
426 | "shopping_duration_formatted":"2m 57s",
427 | "utilities_duration_formatted":"1h 1m"
428 | },
429 | {
430 | "id":1464764400,
431 | "date":"2016-06-01",
432 | "productivity_pulse":55,
433 | "very_productive_percentage":36.4,
434 | "productive_percentage":9.7,
435 | "neutral_percentage":13.6,
436 | "distracting_percentage":22,
437 | "very_distracting_percentage":18.3,
438 | "all_productive_percentage":46.1,
439 | "all_distracting_percentage":40.3,
440 | "uncategorized_percentage":5.8,
441 | "business_percentage":18.2,
442 | "communication_and_scheduling_percentage":24,
443 | "social_networking_percentage":14,
444 | "design_and_composition_percentage":10.9,
445 | "entertainment_percentage":2.5,
446 | "news_percentage":4.7,
447 | "software_development_percentage":7.2,
448 | "reference_and_learning_percentage":4.3,
449 | "shopping_percentage":0,
450 | "utilities_percentage":8.3,
451 | "total_hours":11.12,
452 | "very_productive_hours":4.05,
453 | "productive_hours":1.08,
454 | "neutral_hours":1.51,
455 | "distracting_hours":2.45,
456 | "very_distracting_hours":2.03,
457 | "all_productive_hours":5.12,
458 | "all_distracting_hours":4.48,
459 | "uncategorized_hours":0.65,
460 | "business_hours":2.03,
461 | "communication_and_scheduling_hours":2.67,
462 | "social_networking_hours":1.56,
463 | "design_and_composition_hours":1.22,
464 | "entertainment_hours":0.28,
465 | "news_hours":0.52,
466 | "software_development_hours":0.8,
467 | "reference_and_learning_hours":0.48,
468 | "shopping_hours":0,
469 | "utilities_hours":0.92,
470 | "total_duration_formatted":"11h 7m",
471 | "very_productive_duration_formatted":"4h 2m",
472 | "productive_duration_formatted":"1h 4m",
473 | "neutral_duration_formatted":"1h 30m",
474 | "distracting_duration_formatted":"2h 26m",
475 | "very_distracting_duration_formatted":"2h 1m",
476 | "all_productive_duration_formatted":"5h 7m",
477 | "all_distracting_duration_formatted":"4h 28m",
478 | "uncategorized_duration_formatted":"38m 50s",
479 | "business_duration_formatted":"2h 1m",
480 | "communication_and_scheduling_duration_formatted":"2h 39m",
481 | "social_networking_duration_formatted":"1h 33m",
482 | "design_and_composition_duration_formatted":"1h 13m",
483 | "entertainment_duration_formatted":"16m 51s",
484 | "news_duration_formatted":"31m 19s",
485 | "software_development_duration_formatted":"48m 11s",
486 | "reference_and_learning_duration_formatted":"28m 35s",
487 | "shopping_duration_formatted":"no time",
488 | "utilities_duration_formatted":"55m 22s"
489 | },
490 | {
491 | "id":1464678000,
492 | "date":"2016-05-31",
493 | "productivity_pulse":46,
494 | "very_productive_percentage":25.2,
495 | "productive_percentage":7.3,
496 | "neutral_percentage":17,
497 | "distracting_percentage":31.2,
498 | "very_distracting_percentage":19.4,
499 | "all_productive_percentage":32.5,
500 | "all_distracting_percentage":50.6,
501 | "uncategorized_percentage":7.5,
502 | "business_percentage":15.1,
503 | "communication_and_scheduling_percentage":35.7,
504 | "social_networking_percentage":15.5,
505 | "design_and_composition_percentage":4.6,
506 | "entertainment_percentage":1.2,
507 | "news_percentage":4.6,
508 | "software_development_percentage":5.5,
509 | "reference_and_learning_percentage":5.5,
510 | "shopping_percentage":0.2,
511 | "utilities_percentage":4.6,
512 | "total_hours":10.01,
513 | "very_productive_hours":2.52,
514 | "productive_hours":0.73,
515 | "neutral_hours":1.7,
516 | "distracting_hours":3.12,
517 | "very_distracting_hours":1.94,
518 | "all_productive_hours":3.25,
519 | "all_distracting_hours":5.06,
520 | "uncategorized_hours":0.75,
521 | "business_hours":1.51,
522 | "communication_and_scheduling_hours":3.57,
523 | "social_networking_hours":1.55,
524 | "design_and_composition_hours":0.46,
525 | "entertainment_hours":0.12,
526 | "news_hours":0.46,
527 | "software_development_hours":0.55,
528 | "reference_and_learning_hours":0.55,
529 | "shopping_hours":0.02,
530 | "utilities_hours":0.46,
531 | "total_duration_formatted":"10h",
532 | "very_productive_duration_formatted":"2h 31m",
533 | "productive_duration_formatted":"43m 45s",
534 | "neutral_duration_formatted":"1h 41m",
535 | "distracting_duration_formatted":"3h 7m",
536 | "very_distracting_duration_formatted":"1h 56m",
537 | "all_productive_duration_formatted":"3h 15m",
538 | "all_distracting_duration_formatted":"5h 3m",
539 | "uncategorized_duration_formatted":"44m 57s",
540 | "business_duration_formatted":"1h 30m",
541 | "communication_and_scheduling_duration_formatted":"3h 34m",
542 | "social_networking_duration_formatted":"1h 33m",
543 | "design_and_composition_duration_formatted":"27m 53s",
544 | "entertainment_duration_formatted":"7m 25s",
545 | "news_duration_formatted":"27m 52s",
546 | "software_development_duration_formatted":"32m 45s",
547 | "reference_and_learning_duration_formatted":"32m 50s",
548 | "shopping_duration_formatted":"1m 25s",
549 | "utilities_duration_formatted":"27m 24s"
550 | },
551 | {
552 | "id":1464591600,
553 | "date":"2016-05-30",
554 | "productivity_pulse":52,
555 | "very_productive_percentage":32.5,
556 | "productive_percentage":11.2,
557 | "neutral_percentage":14,
558 | "distracting_percentage":18.3,
559 | "very_distracting_percentage":23.9,
560 | "all_productive_percentage":43.8,
561 | "all_distracting_percentage":42.2,
562 | "uncategorized_percentage":7.8,
563 | "business_percentage":13.4,
564 | "communication_and_scheduling_percentage":20.9,
565 | "social_networking_percentage":16.9,
566 | "design_and_composition_percentage":2.3,
567 | "entertainment_percentage":3.6,
568 | "news_percentage":2.4,
569 | "software_development_percentage":16.9,
570 | "reference_and_learning_percentage":5.7,
571 | "shopping_percentage":2.3,
572 | "utilities_percentage":7.9,
573 | "total_hours":11.87,
574 | "very_productive_hours":3.86,
575 | "productive_hours":1.33,
576 | "neutral_hours":1.66,
577 | "distracting_hours":2.18,
578 | "very_distracting_hours":2.83,
579 | "all_productive_hours":5.19,
580 | "all_distracting_hours":5.01,
581 | "uncategorized_hours":0.93,
582 | "business_hours":1.59,
583 | "communication_and_scheduling_hours":2.48,
584 | "social_networking_hours":2.01,
585 | "design_and_composition_hours":0.27,
586 | "entertainment_hours":0.42,
587 | "news_hours":0.28,
588 | "software_development_hours":2,
589 | "reference_and_learning_hours":0.67,
590 | "shopping_hours":0.28,
591 | "utilities_hours":0.94,
592 | "total_duration_formatted":"11h 51m",
593 | "very_productive_duration_formatted":"3h 51m",
594 | "productive_duration_formatted":"1h 20m",
595 | "neutral_duration_formatted":"1h 39m",
596 | "distracting_duration_formatted":"2h 10m",
597 | "very_distracting_duration_formatted":"2h 49m",
598 | "all_productive_duration_formatted":"5h 11m",
599 | "all_distracting_duration_formatted":"5h",
600 | "uncategorized_duration_formatted":"55m 47s",
601 | "business_duration_formatted":"1h 35m",
602 | "communication_and_scheduling_duration_formatted":"2h 28m",
603 | "social_networking_duration_formatted":"2h",
604 | "design_and_composition_duration_formatted":"16m 7s",
605 | "entertainment_duration_formatted":"25m 25s",
606 | "news_duration_formatted":"16m 44s",
607 | "software_development_duration_formatted":"2h",
608 | "reference_and_learning_duration_formatted":"40m 20s",
609 | "shopping_duration_formatted":"16m 32s",
610 | "utilities_duration_formatted":"56m 28s"
611 | },
612 | {
613 | "id":1464505200,
614 | "date":"2016-05-29",
615 | "productivity_pulse":33,
616 | "very_productive_percentage":17.6,
617 | "productive_percentage":11,
618 | "neutral_percentage":14.7,
619 | "distracting_percentage":0.8,
620 | "very_distracting_percentage":55.8,
621 | "all_productive_percentage":28.6,
622 | "all_distracting_percentage":56.7,
623 | "uncategorized_percentage":11.7,
624 | "business_percentage":3.7,
625 | "communication_and_scheduling_percentage":1.8,
626 | "social_networking_percentage":42.4,
627 | "design_and_composition_percentage":12.3,
628 | "entertainment_percentage":3.2,
629 | "news_percentage":2.5,
630 | "software_development_percentage":1.6,
631 | "reference_and_learning_percentage":5.2,
632 | "shopping_percentage":0,
633 | "utilities_percentage":15.5,
634 | "total_hours":4.37,
635 | "very_productive_hours":0.77,
636 | "productive_hours":0.48,
637 | "neutral_hours":0.64,
638 | "distracting_hours":0.04,
639 | "very_distracting_hours":2.44,
640 | "all_productive_hours":1.25,
641 | "all_distracting_hours":2.47,
642 | "uncategorized_hours":0.51,
643 | "business_hours":0.16,
644 | "communication_and_scheduling_hours":0.08,
645 | "social_networking_hours":1.85,
646 | "design_and_composition_hours":0.54,
647 | "entertainment_hours":0.14,
648 | "news_hours":0.11,
649 | "software_development_hours":0.07,
650 | "reference_and_learning_hours":0.23,
651 | "shopping_hours":0,
652 | "utilities_hours":0.68,
653 | "total_duration_formatted":"4h 22m",
654 | "very_productive_duration_formatted":"46m 8s",
655 | "productive_duration_formatted":"28m 53s",
656 | "neutral_duration_formatted":"38m 33s",
657 | "distracting_duration_formatted":"2m 8s",
658 | "very_distracting_duration_formatted":"2h 26m",
659 | "all_productive_duration_formatted":"1h 15m",
660 | "all_distracting_duration_formatted":"2h 28m",
661 | "uncategorized_duration_formatted":"30m 42s",
662 | "business_duration_formatted":"9m 48s",
663 | "communication_and_scheduling_duration_formatted":"4m 38s",
664 | "social_networking_duration_formatted":"1h 51m",
665 | "design_and_composition_duration_formatted":"32m 14s",
666 | "entertainment_duration_formatted":"8m 25s",
667 | "news_duration_formatted":"6m 40s",
668 | "software_development_duration_formatted":"4m 6s",
669 | "reference_and_learning_duration_formatted":"13m 33s",
670 | "shopping_duration_formatted":"5s",
671 | "utilities_duration_formatted":"40m 41s"
672 | },
673 | {
674 | "id":1464418800,
675 | "date":"2016-05-28",
676 | "productivity_pulse":19,
677 | "very_productive_percentage":3.6,
678 | "productive_percentage":9.6,
679 | "neutral_percentage":14.1,
680 | "distracting_percentage":6.1,
681 | "very_distracting_percentage":66.6,
682 | "all_productive_percentage":13.1,
683 | "all_distracting_percentage":72.8,
684 | "uncategorized_percentage":5,
685 | "business_percentage":1.3,
686 | "communication_and_scheduling_percentage":4.9,
687 | "social_networking_percentage":51.5,
688 | "design_and_composition_percentage":2,
689 | "entertainment_percentage":4.1,
690 | "news_percentage":15.3,
691 | "software_development_percentage":0.3,
692 | "reference_and_learning_percentage":7.6,
693 | "shopping_percentage":0,
694 | "utilities_percentage":8,
695 | "total_hours":2.38,
696 | "very_productive_hours":0.08,
697 | "productive_hours":0.23,
698 | "neutral_hours":0.34,
699 | "distracting_hours":0.15,
700 | "very_distracting_hours":1.58,
701 | "all_productive_hours":0.31,
702 | "all_distracting_hours":1.73,
703 | "uncategorized_hours":0.12,
704 | "business_hours":0.03,
705 | "communication_and_scheduling_hours":0.12,
706 | "social_networking_hours":1.22,
707 | "design_and_composition_hours":0.05,
708 | "entertainment_hours":0.1,
709 | "news_hours":0.36,
710 | "software_development_hours":0.01,
711 | "reference_and_learning_hours":0.18,
712 | "shopping_hours":0,
713 | "utilities_hours":0.19,
714 | "total_duration_formatted":"2h 22m",
715 | "very_productive_duration_formatted":"5m 5s",
716 | "productive_duration_formatted":"13m 38s",
717 | "neutral_duration_formatted":"20m 8s",
718 | "distracting_duration_formatted":"8m 43s",
719 | "very_distracting_duration_formatted":"1h 35m",
720 | "all_productive_duration_formatted":"18m 43s",
721 | "all_distracting_duration_formatted":"1h 43m",
722 | "uncategorized_duration_formatted":"7m 8s",
723 | "business_duration_formatted":"1m 55s",
724 | "communication_and_scheduling_duration_formatted":"6m 59s",
725 | "social_networking_duration_formatted":"1h 13m",
726 | "design_and_composition_duration_formatted":"2m 48s",
727 | "entertainment_duration_formatted":"5m 48s",
728 | "news_duration_formatted":"21m 49s",
729 | "software_development_duration_formatted":"22s",
730 | "reference_and_learning_duration_formatted":"10m 52s",
731 | "shopping_duration_formatted":"2s",
732 | "utilities_duration_formatted":"11m 25s"
733 | },
734 | {
735 | "id":1464332400,
736 | "date":"2016-05-27",
737 | "productivity_pulse":48,
738 | "very_productive_percentage":31.7,
739 | "productive_percentage":4,
740 | "neutral_percentage":16,
741 | "distracting_percentage":23.8,
742 | "very_distracting_percentage":24.5,
743 | "all_productive_percentage":35.7,
744 | "all_distracting_percentage":48.3,
745 | "uncategorized_percentage":6.7,
746 | "business_percentage":16.9,
747 | "communication_and_scheduling_percentage":30.9,
748 | "social_networking_percentage":15.6,
749 | "design_and_composition_percentage":2.9,
750 | "entertainment_percentage":4.9,
751 | "news_percentage":3.8,
752 | "software_development_percentage":12,
753 | "reference_and_learning_percentage":2.1,
754 | "shopping_percentage":0.4,
755 | "utilities_percentage":3.9,
756 | "total_hours":7.91,
757 | "very_productive_hours":2.51,
758 | "productive_hours":0.31,
759 | "neutral_hours":1.27,
760 | "distracting_hours":1.88,
761 | "very_distracting_hours":1.94,
762 | "all_productive_hours":2.82,
763 | "all_distracting_hours":3.82,
764 | "uncategorized_hours":0.53,
765 | "business_hours":1.33,
766 | "communication_and_scheduling_hours":2.44,
767 | "social_networking_hours":1.24,
768 | "design_and_composition_hours":0.23,
769 | "entertainment_hours":0.39,
770 | "news_hours":0.3,
771 | "software_development_hours":0.95,
772 | "reference_and_learning_hours":0.16,
773 | "shopping_hours":0.03,
774 | "utilities_hours":0.31,
775 | "total_duration_formatted":"7h 54m",
776 | "very_productive_duration_formatted":"2h 30m",
777 | "productive_duration_formatted":"18m 45s",
778 | "neutral_duration_formatted":"1h 16m",
779 | "distracting_duration_formatted":"1h 52m",
780 | "very_distracting_duration_formatted":"1h 56m",
781 | "all_productive_duration_formatted":"2h 49m",
782 | "all_distracting_duration_formatted":"3h 49m",
783 | "uncategorized_duration_formatted":"31m 45s",
784 | "business_duration_formatted":"1h 20m",
785 | "communication_and_scheduling_duration_formatted":"2h 26m",
786 | "social_networking_duration_formatted":"1h 14m",
787 | "design_and_composition_duration_formatted":"13m 42s",
788 | "entertainment_duration_formatted":"23m 11s",
789 | "news_duration_formatted":"17m 48s",
790 | "software_development_duration_formatted":"56m 50s",
791 | "reference_and_learning_duration_formatted":"9m 52s",
792 | "shopping_duration_formatted":"1m 48s",
793 | "utilities_duration_formatted":"18m 37s"
794 | },
795 | {
796 | "id":1464246000,
797 | "date":"2016-05-26",
798 | "productivity_pulse":52,
799 | "very_productive_percentage":34.2,
800 | "productive_percentage":9.3,
801 | "neutral_percentage":18.1,
802 | "distracting_percentage":10.6,
803 | "very_distracting_percentage":27.8,
804 | "all_productive_percentage":43.5,
805 | "all_distracting_percentage":38.5,
806 | "uncategorized_percentage":7.7,
807 | "business_percentage":16.6,
808 | "communication_and_scheduling_percentage":18.2,
809 | "social_networking_percentage":20.7,
810 | "design_and_composition_percentage":9.9,
811 | "entertainment_percentage":2.4,
812 | "news_percentage":4.5,
813 | "software_development_percentage":7.7,
814 | "reference_and_learning_percentage":3.6,
815 | "shopping_percentage":0.4,
816 | "utilities_percentage":8.4,
817 | "total_hours":11.27,
818 | "very_productive_hours":3.85,
819 | "productive_hours":1.05,
820 | "neutral_hours":2.04,
821 | "distracting_hours":1.2,
822 | "very_distracting_hours":3.14,
823 | "all_productive_hours":4.9,
824 | "all_distracting_hours":4.33,
825 | "uncategorized_hours":0.87,
826 | "business_hours":1.87,
827 | "communication_and_scheduling_hours":2.05,
828 | "social_networking_hours":2.34,
829 | "design_and_composition_hours":1.12,
830 | "entertainment_hours":0.27,
831 | "news_hours":0.5,
832 | "software_development_hours":0.86,
833 | "reference_and_learning_hours":0.41,
834 | "shopping_hours":0.04,
835 | "utilities_hours":0.94,
836 | "total_duration_formatted":"11h 16m",
837 | "very_productive_duration_formatted":"3h 51m",
838 | "productive_duration_formatted":"1h 2m",
839 | "neutral_duration_formatted":"2h 2m",
840 | "distracting_duration_formatted":"1h 11m",
841 | "very_distracting_duration_formatted":"3h 8m",
842 | "all_productive_duration_formatted":"4h 53m",
843 | "all_distracting_duration_formatted":"4h 20m",
844 | "uncategorized_duration_formatted":"52m 13s",
845 | "business_duration_formatted":"1h 52m",
846 | "communication_and_scheduling_duration_formatted":"2h 2m",
847 | "social_networking_duration_formatted":"2h 20m",
848 | "design_and_composition_duration_formatted":"1h 6m",
849 | "entertainment_duration_formatted":"15m 58s",
850 | "news_duration_formatted":"30m 12s",
851 | "software_development_duration_formatted":"51m 45s",
852 | "reference_and_learning_duration_formatted":"24m 22s",
853 | "shopping_duration_formatted":"2m 35s",
854 | "utilities_duration_formatted":"56m 39s"
855 | },
856 | {
857 | "id":1464159600,
858 | "date":"2016-05-25",
859 | "productivity_pulse":55,
860 | "very_productive_percentage":33.1,
861 | "productive_percentage":11.8,
862 | "neutral_percentage":21.1,
863 | "distracting_percentage":13.2,
864 | "very_distracting_percentage":20.9,
865 | "all_productive_percentage":44.8,
866 | "all_distracting_percentage":34.1,
867 | "uncategorized_percentage":12.4,
868 | "business_percentage":6.8,
869 | "communication_and_scheduling_percentage":17.8,
870 | "social_networking_percentage":15.5,
871 | "design_and_composition_percentage":4,
872 | "entertainment_percentage":2.1,
873 | "news_percentage":2.6,
874 | "software_development_percentage":22.3,
875 | "reference_and_learning_percentage":2.9,
876 | "shopping_percentage":0.2,
877 | "utilities_percentage":13.5,
878 | "total_hours":8.07,
879 | "very_productive_hours":2.67,
880 | "productive_hours":0.95,
881 | "neutral_hours":1.7,
882 | "distracting_hours":1.06,
883 | "very_distracting_hours":1.68,
884 | "all_productive_hours":3.62,
885 | "all_distracting_hours":2.75,
886 | "uncategorized_hours":1,
887 | "business_hours":0.55,
888 | "communication_and_scheduling_hours":1.44,
889 | "social_networking_hours":1.25,
890 | "design_and_composition_hours":0.32,
891 | "entertainment_hours":0.17,
892 | "news_hours":0.21,
893 | "software_development_hours":1.8,
894 | "reference_and_learning_hours":0.24,
895 | "shopping_hours":0.01,
896 | "utilities_hours":1.09,
897 | "total_duration_formatted":"8h 3m",
898 | "very_productive_duration_formatted":"2h 40m",
899 | "productive_duration_formatted":"56m 58s",
900 | "neutral_duration_formatted":"1h 42m",
901 | "distracting_duration_formatted":"1h 3m",
902 | "very_distracting_duration_formatted":"1h 41m",
903 | "all_productive_duration_formatted":"3h 36m",
904 | "all_distracting_duration_formatted":"2h 44m",
905 | "uncategorized_duration_formatted":"1h",
906 | "business_duration_formatted":"32m 43s",
907 | "communication_and_scheduling_duration_formatted":"1h 26m",
908 | "social_networking_duration_formatted":"1h 14m",
909 | "design_and_composition_duration_formatted":"19m 9s",
910 | "entertainment_duration_formatted":"10m 7s",
911 | "news_duration_formatted":"12m 34s",
912 | "software_development_duration_formatted":"1h 48m",
913 | "reference_and_learning_duration_formatted":"14m 8s",
914 | "shopping_duration_formatted":"47s",
915 | "utilities_duration_formatted":"1h 5m"
916 | }
917 | ]
--------------------------------------------------------------------------------
/tests/RescueTime/Tests/Fakes/interval.json:
--------------------------------------------------------------------------------
1 | {
2 | "notes": "data is an array of arrays (rows), column names for rows in row_headers",
3 | "row_headers": [
4 | "Date",
5 | "Time Spent (seconds)",
6 | "Number of People",
7 | "Activity",
8 | "Category",
9 | "Productivity"
10 | ],
11 | "rows": [
12 | [
13 | "2013-08-11T18:00:00",
14 | 91,
15 | 1,
16 | "sublime text 2",
17 | "Editing & IDEs",
18 | 2
19 | ],
20 | [
21 | "2013-08-11T18:00:00",
22 | 69,
23 | 1,
24 | "iTerm",
25 | "Systems Operations",
26 | 2
27 | ],
28 | [
29 | "2013-08-11T18:00:00",
30 | 20,
31 | 1,
32 | "rescuetime.com",
33 | "Intelligence",
34 | 2
35 | ],
36 | [
37 | "2013-08-11T18:00:00",
38 | 12,
39 | 1,
40 | "RescueTime",
41 | "Intelligence",
42 | 2
43 | ],
44 | [
45 | "2013-08-11T18:00:00",
46 | 7,
47 | 1,
48 | "evernote",
49 | "Intelligence",
50 | 2
51 | ],
52 | [
53 | "2013-08-11T19:00:00",
54 | 220,
55 | 1,
56 | "php.net",
57 | "Engineering & Technology",
58 | 1
59 | ],
60 | [
61 | "2013-08-11T19:00:00",
62 | 191,
63 | 1,
64 | "spotify",
65 | "General Entertainment",
66 | -2
67 | ],
68 | [
69 | "2013-08-11T19:00:00",
70 | 32,
71 | 1,
72 | "mirkoborivojevic.com",
73 | "Uncategorized",
74 | 0
75 | ],
76 | [
77 | "2013-08-11T19:00:00",
78 | 10,
79 | 1,
80 | "Gmail",
81 | "Email",
82 | 0
83 | ],
84 | [
85 | "2013-08-11T19:00:00",
86 | 6,
87 | 1,
88 | "google.rs",
89 | "Search",
90 | 0
91 | ],
92 | [
93 | "2013-08-11T20:00:00",
94 | 175,
95 | 1,
96 | "teamviewer",
97 | "General Utilities",
98 | 1
99 | ],
100 | [
101 | "2013-08-11T20:00:00",
102 | 60,
103 | 1,
104 | "github.com",
105 | "General Software Development",
106 | 2
107 | ],
108 | [
109 | "2013-08-11T20:00:00",
110 | 23,
111 | 1,
112 | "Steam",
113 | "Games",
114 | -2
115 | ],
116 | [
117 | "2013-08-12T21:00:00",
118 | 3,
119 | 1,
120 | "gist.github.com",
121 | "General Software Development",
122 | 2
123 | ]
124 | ]
125 | }
--------------------------------------------------------------------------------
/tests/RescueTime/Tests/Fakes/member.json:
--------------------------------------------------------------------------------
1 | {
2 | "notes": "data is an array of arrays (rows), column names for rows in row_headers",
3 | "row_headers": [
4 | "Person",
5 | "Time Spent (seconds)",
6 | "Activity",
7 | "Category",
8 | "Productivity"
9 | ],
10 | "rows": [
11 | [
12 | "Mirko",
13 | 10038,
14 | "sublime text 2",
15 | "Editing & IDEs",
16 | 2
17 | ],
18 | [
19 | "Mirko",
20 | 1810,
21 | "basecamp.com",
22 | "Design & Planning",
23 | 2
24 | ],
25 | [
26 | "Mirko",
27 | 1670,
28 | "iTerm",
29 | "Systems Operations",
30 | 2
31 | ],
32 | [
33 | "Mirko",
34 | 1300,
35 | "Gmail",
36 | "Email",
37 | 0
38 | ],
39 | [
40 | "Mirko",
41 | 857,
42 | "rescuetime.com",
43 | "Intelligence",
44 | 2
45 | ],
46 | [
47 | "Mirko",
48 | 512,
49 | "kmplayer",
50 | "General Entertainment",
51 | -2
52 | ],
53 | [
54 | "Mirko",
55 | 423,
56 | "mirkoborivojevic.com",
57 | "Uncategorized",
58 | 0
59 | ],
60 | [
61 | "Mirko",
62 | 420,
63 | "mysqlworkbench",
64 | "General Software Development",
65 | 2
66 | ],
67 | [
68 | "Mirko",
69 | 419,
70 | "Hosted Google Docs",
71 | "Writing",
72 | 2
73 | ],
74 | [
75 | "Mirko",
76 | 418,
77 | "evernote",
78 | "Intelligence",
79 | 2
80 | ],
81 | [
82 | "Mirko",
83 | 365,
84 | "google.com/analytics",
85 | "General Software Development",
86 | 2
87 | ],
88 | [
89 | "Mirko",
90 | 313,
91 | "github.com",
92 | "General Software Development",
93 | 2
94 | ],
95 | [
96 | "Mirko",
97 | 305,
98 | "google.rs",
99 | "Search",
100 | 0
101 | ],
102 | [
103 | "Mirko",
104 | 291,
105 | "teamviewer",
106 | "General Utilities",
107 | 1
108 | ],
109 | [
110 | "Mirko",
111 | 260,
112 | "spotify",
113 | "General Entertainment",
114 | -2
115 | ],
116 | [
117 | "Mirko",
118 | 141,
119 | "iTunes",
120 | "Music",
121 | -2
122 | ],
123 | [
124 | "Mirko",
125 | 94,
126 | "Twitter",
127 | "General Social Networking",
128 | -2
129 | ]
130 | ]
131 | }
--------------------------------------------------------------------------------
/tests/RescueTime/Tests/Fakes/rank.json:
--------------------------------------------------------------------------------
1 | {
2 | "notes": "data is an array of arrays (rows), column names for rows in row_headers",
3 | "row_headers": [
4 | "Rank",
5 | "Time Spent (seconds)",
6 | "Number of People",
7 | "Activity",
8 | "Category",
9 | "Productivity"
10 | ],
11 | "rows": [
12 | [
13 | 1,
14 | 10038,
15 | 1,
16 | "sublime text 2",
17 | "Editing & IDEs",
18 | 2
19 | ],
20 | [
21 | 2,
22 | 1810,
23 | 1,
24 | "basecamp.com",
25 | "Design & Planning",
26 | 2
27 | ],
28 | [
29 | 3,
30 | 1300,
31 | 1,
32 | "Gmail",
33 | "Email",
34 | 0
35 | ],
36 | [
37 | 4,
38 | 857,
39 | 1,
40 | "rescuetime.com",
41 | "Intelligence",
42 | 2
43 | ],
44 | [
45 | 5,
46 | 512,
47 | 1,
48 | "kmplayer",
49 | "General Entertainment",
50 | -2
51 | ],
52 | [
53 | 6,
54 | 423,
55 | 1,
56 | "mirkoborivojevic.com",
57 | "Uncategorized",
58 | 0
59 | ],
60 | [
61 | 7,
62 | 420,
63 | 1,
64 | "mysqlworkbench",
65 | "General Software Development",
66 | 2
67 | ],
68 | [
69 | 8,
70 | 419,
71 | 1,
72 | "Hosted Google Docs",
73 | "Writing",
74 | 2
75 | ],
76 | [
77 | 9,
78 | 418,
79 | 1,
80 | "evernote",
81 | "Intelligence",
82 | 2
83 | ],
84 | [
85 | 10,
86 | 365,
87 | 1,
88 | "google.com/analytics",
89 | "General Software Development",
90 | 2
91 | ],
92 | [
93 | 11,
94 | 313,
95 | 1,
96 | "github.com",
97 | "General Software Development",
98 | 2
99 | ],
100 | [
101 | 12,
102 | 305,
103 | 1,
104 | "google.rs",
105 | "Search",
106 | 0
107 | ],
108 | [
109 | 13,
110 | 291,
111 | 1,
112 | "teamviewer",
113 | "General Utilities",
114 | 1
115 | ],
116 | [
117 | 14,
118 | 260,
119 | 1,
120 | "spotify",
121 | "General Entertainment",
122 | -2
123 | ],
124 | [
125 | 15,
126 | 141,
127 | 1,
128 | "iTunes",
129 | "Music",
130 | -2
131 | ]
132 | ]
133 | }
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | add('RescueTime\Tests', __DIR__);
4 |
--------------------------------------------------------------------------------