├── __init__.py
├── runtime.txt
├── personal_dashboard
├── __init__.py
├── quotes.py
├── chess.py
├── personal_info_template.py
├── todoist.py
├── spotify.py
├── withings.py
├── books.py
├── articles.py
├── toggl.py
├── meditation.py
├── moves.py
└── rescuetime.py
├── Procfile
├── .env
├── static
├── favicon.ico
├── js
│ └── canvasjs
│ │ ├── assets
│ │ ├── fonts
│ │ │ ├── roboto-v15-latin-300.woff
│ │ │ ├── roboto-v15-latin-500.woff
│ │ │ ├── roboto-v15-latin-700.woff
│ │ │ ├── roboto-v15-latin-300.woff2
│ │ │ ├── roboto-v15-latin-500.woff2
│ │ │ ├── roboto-v15-latin-700.woff2
│ │ │ ├── roboto-v15-latin-regular.woff
│ │ │ ├── roboto-v15-latin-regular.woff2
│ │ │ └── font-roboto.css
│ │ ├── font-awesome
│ │ │ ├── fonts
│ │ │ │ ├── FontAwesome.otf
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ └── fontawesome-webfont.woff2
│ │ │ ├── less
│ │ │ │ ├── screen-reader.less
│ │ │ │ ├── fixed-width.less
│ │ │ │ ├── larger.less
│ │ │ │ ├── list.less
│ │ │ │ ├── core.less
│ │ │ │ ├── stacked.less
│ │ │ │ ├── font-awesome.less
│ │ │ │ ├── bordered-pulled.less
│ │ │ │ ├── rotated-flipped.less
│ │ │ │ ├── path.less
│ │ │ │ ├── animated.less
│ │ │ │ └── mixins.less
│ │ │ ├── scss
│ │ │ │ ├── _fixed-width.scss
│ │ │ │ ├── _screen-reader.scss
│ │ │ │ ├── _larger.scss
│ │ │ │ ├── _list.scss
│ │ │ │ ├── _core.scss
│ │ │ │ ├── font-awesome.scss
│ │ │ │ ├── _stacked.scss
│ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ ├── _path.scss
│ │ │ │ ├── _animated.scss
│ │ │ │ └── _mixins.scss
│ │ │ └── HELP-US-OUT.txt
│ │ ├── economy-dashboard
│ │ │ ├── images
│ │ │ │ └── paper-texture.png
│ │ │ └── styles.css
│ │ ├── jquery.scrollspeed
│ │ │ ├── jquery.scrollspeed.min.js
│ │ │ └── jquery.scrollspeed.js
│ │ ├── jquery.inview
│ │ │ └── jquery.inview.min.js
│ │ ├── no-ui-slider
│ │ │ └── nouislider.min.css
│ │ └── web-analytics
│ │ │ └── style.css
│ │ ├── instruction.txt
│ │ ├── canvasjs-non-commercial-1.9..textClipping
│ │ ├── examples
│ │ ├── 04-pie-chart
│ │ │ ├── basic-pie-chart.html
│ │ │ └── pie-chart-with-index-label.html
│ │ ├── 06-doughnut-chart
│ │ │ ├── basic-doughnut-chart.html
│ │ │ ├── doughnut-chart-with-explode-on-click-disabled.html
│ │ │ └── doughnut-chart-with-index-label.html
│ │ ├── 03-area-chart
│ │ │ ├── area-chart-with-opacity.html
│ │ │ ├── area-chart-with-line-thickness.html
│ │ │ ├── basic-area-chart.html
│ │ │ ├── area-chart-with-date-time-axis.html
│ │ │ └── area-chart-with-xy-zoom-type.html
│ │ ├── 07-spline-chart
│ │ │ ├── basic-spline-chart.html
│ │ │ └── spline-chart-with-marker-customization.html
│ │ ├── 20-range-area-chart
│ │ │ ├── basic-range-area-chart.html
│ │ │ └── range-area-with-null-data.html
│ │ ├── 01-line-chart
│ │ │ ├── line-chart-with-stripline.html
│ │ │ ├── line-chart-with-null(empty)-data.html
│ │ │ ├── line-chart-with-line-customization.html
│ │ │ ├── basic-line-chart.html
│ │ │ ├── line-chart-with-zooming.html
│ │ │ ├── line-chart-with-date-time-axis.html
│ │ │ ├── line-chart-with-xy-zoom-type.html
│ │ │ └── multi-series-line-chart.html
│ │ ├── 05-bar-chart
│ │ │ ├── basic-bar-chart.html
│ │ │ └── bar-chart-with-stripline.html
│ │ ├── 21-range-spline-area-chart
│ │ │ ├── basic-range-spline-area_-chart.html
│ │ │ └── range-spline-area-with-line-chart.html
│ │ ├── 17-spline-area-chart
│ │ │ ├── spline-area-chart-with-stripline.html
│ │ │ └── basic-spline-area-chart.html
│ │ ├── 25 -jquery-plugin
│ │ │ └── basic-jquery-line-chart.html
│ │ ├── 02-column-chart
│ │ │ ├── column-chart-with-index-label-customization.html
│ │ │ ├── basic-column-chart.html
│ │ │ └── multi-series-column-chart.html
│ │ ├── 24-stacked-column-100-chart
│ │ │ ├── basic-stacked-column-100-chart.html
│ │ │ └── stacked-column-100-with-index-label.html
│ │ ├── 18-range-bar-chart
│ │ │ ├── basic-range-bar-chart.html
│ │ │ └── range-bar-with-index-label.html
│ │ ├── 15-step-line-chart
│ │ │ ├── basic-step-line-chart.html
│ │ │ └── multi-series-step-line-chart.html
│ │ ├── 16-step-area-chart
│ │ │ └── basic-step-area-chart.html
│ │ ├── 26-some-common-options-across-all-chart-types
│ │ │ ├── export-chart.html
│ │ │ ├── culture.html
│ │ │ ├── chart-with-animation.html
│ │ │ ├── hide-and-unhide-data-series-from-legend.html
│ │ │ └── combination-charts.html
│ │ ├── 19-range-column-chart
│ │ │ ├── basic-range-column-chart.html
│ │ │ └── range-column-with-index-label.html
│ │ ├── 08-bubble-chart
│ │ │ ├── basic-bubble-chart.html
│ │ │ └── bubble-chart-with-tooltip-customization.html
│ │ ├── 13-candlestick-chart
│ │ │ ├── candle-stick-chart-with-rising-color-and-tooltip-customization.html
│ │ │ └── basic-candle-stick-chart.html
│ │ ├── 09-stacked-column-chart
│ │ │ ├── basic-stacked-column-chart.html
│ │ │ └── stacked-column-with-total-shown-on-top.html
│ │ ├── 14-ohlc(stock)-chart
│ │ │ ├── basic-ohlc-chart.html
│ │ │ └── ohlc-chart-with-tooltip-customization.html
│ │ ├── 23-stacked-bar-100-chart
│ │ │ ├── basic-stacked-bar-100-chart.html
│ │ │ └── stacked-bar-100-with-index-label.html
│ │ ├── 22-stacked-area-100-chart
│ │ │ ├── stacked-area-100-with-index-label.html
│ │ │ └── basic-stacked-area-100-chart.html
│ │ ├── 12-scatter-chart
│ │ │ ├── basic-scatter-chart.html
│ │ │ └── multi-series-scatter-chart.html
│ │ ├── 10-stacked-bar-chart
│ │ │ ├── basic-stacked-bar-chart.html
│ │ │ └── stacked-bar-chart-with-index-label.html
│ │ └── 11-stacked-area-chart
│ │ │ ├── basic -stacked-area-chart.html
│ │ │ └── stacked-area-chart-with-shared-tooltip.html
│ │ └── license.txt
└── css
│ └── styles.css
├── manage.py
├── config.py
├── models.py
├── requirements.txt
├── .gitignore
└── README.md
/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.6.3
2 |
--------------------------------------------------------------------------------
/personal_dashboard/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn app:app
2 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | DATABASE_URL="postgresql://localhost/qself_dashboard"
2 | APP_SETTINGS="config.DevelopmentConfig"
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/favicon.ico
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-300.woff
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-500.woff
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-700.woff
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-300.woff2
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-500.woff2
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-700.woff2
--------------------------------------------------------------------------------
/static/js/canvasjs/instruction.txt:
--------------------------------------------------------------------------------
1 | For standalone version include canvasjs.min.js
2 | For jQuery version include jquery.canvasjs.min.js
3 |
4 | ** DO NOT include both the files **
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-regular.woff
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/roboto-v15-latin-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/fonts/roboto-v15-latin-regular.woff2
--------------------------------------------------------------------------------
/static/js/canvasjs/canvasjs-non-commercial-1.9..textClipping:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/canvasjs-non-commercial-1.9..textClipping
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/economy-dashboard/images/paper-texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/economy-dashboard/images/paper-texture.png
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Andreilys/personal_dashboard/HEAD/static/js/canvasjs/assets/font-awesome/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only(); }
5 | .sr-only-focusable { @include sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/HELP-US-OUT.txt:
--------------------------------------------------------------------------------
1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
3 | comprehensive icon sets or copy and paste your own.
4 |
5 | Please. Check it out.
6 |
7 | -Dave Gandy
8 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import Flask
3 | from flask_script import Manager
4 | from flask_migrate import Migrate, MigrateCommand
5 |
6 | from app import app, db
7 |
8 |
9 | app.config.from_object(os.environ['APP_SETTINGS'])
10 |
11 | migrate = Migrate(app, db)
12 | manager = Manager(app)
13 |
14 | manager.add_command('db', MigrateCommand)
15 |
16 |
17 | if __name__ == '__main__':
18 | manager.run()
19 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | basedir = os.path.abspath(os.path.dirname(__file__))
3 |
4 |
5 | class Config(object):
6 | DEBUG = False
7 | TESTING = False
8 | CSRF_ENABLED = True
9 | SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
10 |
11 | class ProductionConfig(Config):
12 | DEBUG = False
13 |
14 |
15 | class StagingConfig(Config):
16 | DEVELOPMENT = True
17 | DEBUG = True
18 |
19 |
20 | class DevelopmentConfig(Config):
21 | DEVELOPMENT = True
22 | DEBUG = True
23 |
24 |
25 | class TestingConfig(Config):
26 | TESTING = True
27 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 | @import "screen-reader";
19 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 | @import "screen-reader.less";
19 |
--------------------------------------------------------------------------------
/personal_dashboard/quotes.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | class Quote():
4 | def __init__(self):
5 | #Quote generated from https://quotes.rest/#!/qod/get_qod_categories
6 | headers = { "Accept": "application/json"}
7 | r = requests.get('https://quotes.rest/qod', headers=headers)
8 | #Quotes has a daily limit that we exceed unforunately
9 | try:
10 | self.content = r.json()["contents"]["quotes"][0]["quote"]
11 | self.author = r.json()["contents"]["quotes"][0]["author"]
12 | except:
13 | self.content = "Everything we hear is an opinion, not a fact. Everything we see is a perspective, not the truth."
14 | self.author = "Marcus Aurelius"
15 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix} {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .@{fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .#{$fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/personal_dashboard/chess.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | #The chess class is used to get the number of wins/draws/losses (get_games()) as
4 | # well as the current rating for blitz chess on lichess.org
5 | class Chess():
6 | def __init__(self):
7 | r = requests.get('https://en.lichess.org/api/user/andreilys').json()
8 | self.draw = r['count']['draw']
9 | self.win = r['count']['win']
10 | self.loss =r['count']['loss']
11 | self.rating = r['perfs']['blitz']['rating']
12 | self.url = r['url']
13 |
14 |
15 | def get_games(self):
16 | chess_dict = {"wins" : self.win, "losses" : self.loss, "draws" : self.draw}
17 | return chess_dict
18 |
19 |
20 | def get_rating(self):
21 | return "Blitz Chess rating: {1}".format(self.url, self.rating)
22 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/04-pie-chart/basic-pie-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
29 |
30 | CanvasJS Example
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/06-doughnut-chart/basic-doughnut-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
29 |
30 | CanvasJS Example
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/jquery.scrollspeed/jquery.scrollspeed.min.js:
--------------------------------------------------------------------------------
1 | !function(a){jQuery.scrollSpeed=function(b,c,d){var k,l,m,e=a(document),f=a(window),g=a("html, body"),h=d||"default",i=0,j=!1;return!(window.navigator.msPointerEnabled||a("#isIE").length>0)&&void f.on("mousewheel DOMMouseScroll",function(a){var d=a.originalEvent.wheelDeltaY,n=a.originalEvent.detail;return k=e.height()>f.height(),l=e.width()>f.width(),j=!0,k&&(m=f.height(),(d<0||n>0)&&(i=i+m>=e.height()?i:i+=b),(d>0||n<0)&&(i=i<=0?0:i-=b),g.stop().animate({scrollTop:i},c,h,function(){j=!1})),l&&(m=f.width(),(d<0||n>0)&&(i=i+m>=e.width()?i:i+=b),(d>0||n<0)&&(i=i<=0?0:i-=b),g.stop().animate({scrollLeft:i},c,h,function(){j=!1})),!1}).on("scroll",function(){k&&!j&&(i=f.scrollTop()),l&&!j&&(i=f.scrollLeft())}).on("resize",function(){k&&!j&&(m=f.height()),l&&!j&&(m=f.width())})},jQuery.easing.default=function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c}}(jQuery);
--------------------------------------------------------------------------------
/static/js/canvasjs/license.txt:
--------------------------------------------------------------------------------
1 | *
2 | * @preserve CanvasJS HTML5 & JavaScript Charts - v1.9.10 GA - https://canvasjs.com/
3 | * Copyright 2017 fenopix
4 | *
5 | * --------------------- License Information --------------------
6 | * CanvasJS is a commercial product which requires purchase of license. Without a commercial license you can use it for evaluation purposes for upto 30 days. Please refer to the following link for further details.
7 | * https://canvasjs.com/license-canvasjs/
8 | *
9 | *
10 | *---------------------Free for Non-Commercial Use--------------------
11 | *
12 | *For non-commercial purposes you can use the software for free under Creative Commons Attribution-NonCommercial 3.0 License.
13 | *A credit Link is added to the bottom right of the chart which should be preserved. Refer to the following link for further details on the same.
14 | * http://creativecommons.org/licenses/by-nc/3.0/deed.en_US
15 | *
16 | *
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/models.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | from app import db
3 | from sqlalchemy import Column, Integer, DateTime, JSON
4 |
5 | class GoalCompletion(db.Model):
6 | __tablename__ = 'dates_completed_goals'
7 | id = db.Column(db.Integer, primary_key=True)
8 | date = db.Column(JSON)
9 |
10 | def __init__(self, date):
11 | self.date = date
12 |
13 | def __repr__(self):
14 | return ''.format(self.id)
15 |
16 |
17 | class PersonalData(db.Model):
18 | __tablename__ = 'personal_data'
19 | id = db.Column(db.Integer, primary_key=True)
20 | personal_data_dictionary = db.Column(JSON)
21 | created_date = db.Column(DateTime, default=datetime.datetime.utcnow)
22 |
23 | def __init__(self, personal_data_dictionary, created_date):
24 | self.personal_data_dictionary = personal_data_dictionary
25 | self.created_date = created_date
26 |
27 | def __repr__(self):
28 | return ''.format(self.id)
29 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/03-area-chart/area-chart-with-opacity.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
32 |
33 | CanvasJS Example
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/07-spline-chart/basic-spline-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
29 |
30 | CanvasJS Example
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/20-range-area-chart/basic-range-area-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
33 |
34 | CanvasJS Example
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/03-area-chart/area-chart-with-line-thickness.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
33 |
34 | CanvasJS Example
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/personal_dashboard/personal_info_template.py:
--------------------------------------------------------------------------------
1 | lRESCUETIME_API_KEY = RESCUETIME_API_KEY
2 | TODOIST = {"email" : EMAIL, "password" : PASSWORD}
3 | SPOTIFY = {"email" : EMAIL, 'client_id' : CLIENT_ID, 'client_secret': CLIENT_SECRET, 'redirect_uri': WHAT_YOU_ENTER_ON_SPOTIFY}
4 | MOVES_KEYS = {'client_id':CLIENT_ID, 'client_secret':CLIENT_SECRET, 'redirect_uri': WHAT_YOU_ENTER_ON_MOVES}
5 | WITHINGS_KEYS = {'API_KEY': API_KEY, 'API_SECRET' : API_SECRET}
6 | TOGGL_API_TOKEN = TOGGL_API_TOKEN
7 | STEPS_GOAL = STEP_GOAL
8 | FOCUS_GOAL = FOCUS_GOAL
9 | UNPRODUCTIVITY_GOAL = UNPRODUCTIVITY_GOAL
10 | #Get the JSON share link from wakatime, similar to this (https://wakatime.com/share/@0c62f2ad-9fa5-43c7-a08f-7b1562918a7d/43cd4128-5361-43db-b51b-d965e3c575a5.json):
11 | WAKATIME_CODING_TIME = JSON_LINK
12 | WAKATIME_CODING_TYPE = JSON_LINK
13 | MEDITATION_GOAL = 30
14 | STEPS_GOAL = 5000
15 | UNPRODUCTIVITY_GOAL = 1
16 | INSIGHT_MEDITATION_LOGIN = {'username' : 'user', 'password' : 'pw'}
17 | GOODREADS_INFO = {'user_id': '1', 'api_key' : '1'}
18 | MEDIUM_USER = 'a'
19 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-stripline.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
38 |
39 | CanvasJS Example
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-null(empty)-data.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
32 |
33 | CanvasJS Example
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-line-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
32 |
33 | CanvasJS Example
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/05-bar-chart/basic-bar-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
35 | CanvasJS Example
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/07-spline-chart/spline-chart-with-marker-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
30 |
31 | CanvasJS Example
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/basic-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 | CanvasJS Example
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/03-area-chart/basic-area-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 | CanvasJS Example
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | ajax==3.0.0
2 | alembic==0.9.6
3 | aniso8601==1.3.0
4 | arrow==0.10.0
5 | BitBucket==0.4a0
6 | blinker==1.4
7 | certifi==2017.7.27.1
8 | chardet==3.0.4
9 | click==6.7
10 | decorator==4.1.2
11 | django-appconf==1.0.2
12 | enum-compat==0.0.2
13 | eventlet==0.20.1
14 | Flask==0.12.3
15 | Flask-DebugToolbar==0.10.1
16 | Flask-Migrate==2.1.1
17 | Flask-RESTful==0.3.6
18 | Flask-Script==2.0.6
19 | Flask-SocketIO==2.9.2
20 | Flask-SQLAlchemy==2.3.1
21 | gevent==1.2.1
22 | gevent-websocket==0.9.5
23 | greenlet==0.4.12
24 | gunicorn==19.7.1
25 | idna==2.6
26 | itsdangerous==0.24
27 | Jinja2>=2.10.1
28 | Lector==0.0.3
29 | Mako==1.0.7
30 | MarkupSafe==0.23
31 | moves==0.1
32 | nokia==0.4.0
33 | numpy==1.13.1
34 | oauthlib==2.0.4
35 | pandas==0.20.3
36 | psycopg2==2.7.3.1
37 | pyperclip==1.5.27
38 | python-dateutil==2.6.1
39 | python-dotenv==0.7.1
40 | python-editor==1.0.3
41 | python-engineio==1.7.0
42 | python-socketio==1.8.0
43 | pytodoist==2.1.0
44 | pytz==2017.2
45 | rauth==0.7.3
46 | requests==2.20.0
47 | requests-oauth==0.4.1
48 | requests-oauthlib==0.8.0
49 | six==1.10.0
50 | spotipy==2.4.4
51 | SQLAlchemy>=1.3.0
52 | urllib3>=1.23
53 | Werkzeug==0.11.15
54 | xmltodict==0.11.0
55 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/21-range-spline-area-chart/basic-range-spline-area_-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
35 |
36 | CanvasJS Example
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/04-pie-chart/pie-chart-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
35 | CanvasJS Example
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/06-doughnut-chart/doughnut-chart-with-explode-on-click-disabled.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
31 |
32 | CanvasJS Example
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/17-spline-area-chart/spline-area-chart-with-stripline.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/25 -jquery-plugin/basic-jquery-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CanvasJS Example - jQuery Line Chart
5 |
6 |
7 |
8 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/02-column-chart/column-chart-with-index-label-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
35 | CanvasJS Example
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/fonts/font-roboto.css:
--------------------------------------------------------------------------------
1 | /* roboto-300 - latin */
2 | @font-face {
3 | font-family: 'Roboto';
4 | font-style: normal;
5 | font-weight: 300;
6 | src: local('Roboto Light'), local('Roboto-Light'), url('roboto-v15-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ url('../../fonts/roboto-v15-latin-300.woff') format('woff');
7 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
8 | }
9 | /* roboto-regular - latin */
10 | @font-face {
11 | font-family: 'Roboto';
12 | font-style: normal;
13 | font-weight: 400;
14 | src: local('Roboto'), local('Roboto-Regular'), url('roboto-v15-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ url('../../fonts/roboto-v15-latin-regular.woff') format('woff');
15 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
16 | }
17 | /* roboto-500 - latin */
18 | @font-face {
19 | font-family: 'Roboto';
20 | font-style: normal;
21 | font-weight: 500;
22 | src: local('Roboto Medium'), local('Roboto-Medium'), url('roboto-v15-latin-500.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ url('../../fonts/roboto-v15-latin-500.woff') format('woff');
23 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
24 | }
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/24-stacked-column-100-chart/basic-stacked-column-100-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-zooming.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/02-column-chart/basic-column-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
35 | CanvasJS Example
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/18-range-bar-chart/basic-range-bar-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/03-area-chart/area-chart-with-date-time-axis.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
35 | CanvasJS Example
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/05-bar-chart/bar-chart-with-stripline.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
41 |
42 | CanvasJS Example
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/06-doughnut-chart/doughnut-chart-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-date-time-axis.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 | CanvasJS Example
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/18-range-bar-chart/range-bar-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
41 |
42 | CanvasJS Example
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/line-chart-with-xy-zoom-type.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
46 | CanvasJS Example
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/03-area-chart/area-chart-with-xy-zoom-type.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
46 | CanvasJS Example
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/15-step-line-chart/basic-step-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
40 |
41 | CanvasJS Example
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/jquery.inview/jquery.inview.min.js:
--------------------------------------------------------------------------------
1 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){function i(){var b,c,d={height:f.innerHeight,width:f.innerWidth};return d.height||(b=e.compatMode,(b||!a.support.boxModel)&&(c="CSS1Compat"===b?g:e.body,d={height:c.clientHeight,width:c.clientWidth})),d}function j(){return{top:f.pageYOffset||g.scrollTop||e.body.scrollTop,left:f.pageXOffset||g.scrollLeft||e.body.scrollLeft}}function k(){if(b.length){var e=0,f=a.map(b,function(a){var b=a.data.selector,c=a.$element;return b?c.find(b):c});for(c=c||i(),d=d||j();ed.top&&l.topd.left&&l.left
2 |
3 |
4 |
41 |
42 | CanvasJS Example
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/26-some-common-options-across-all-chart-types/export-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
38 |
39 |
40 | CanvasJS Example
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/17-spline-area-chart/basic-spline-area-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
40 |
41 | CanvasJS Example
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/26-some-common-options-across-all-chart-types/culture.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
43 |
44 | CanvasJS Example
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/19-range-column-chart/basic-range-column-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
45 |
46 | CanvasJS Example
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/personal_dashboard/todoist.py:
--------------------------------------------------------------------------------
1 | from pytodoist import todoist
2 | from .personal_info import TODOIST
3 |
4 | #Todoist class has three methods: get_past_seven_completed_task which
5 | #returns the number of tasks completed in the last 7 days, get_today_completed_task
6 | # which returns the number of tasks finished today, and get_total_tasks which
7 | # returns the number of total tasks left
8 | class Todoist():
9 | def __init__(self):
10 | #This is meant as a safe guard against too many todoist API calls
11 | try:
12 | self.user = todoist.login(TODOIST["email"], TODOIST["password"])
13 | self.productivity = self.user.get_productivity_stats()
14 | self.days_items = self.productivity["days_items"]
15 | except:
16 | self.days_items = [{"total_completed" : 0}]
17 |
18 |
19 | def get_past_seven_completed_tasks(self):
20 | completed_tasks = 0
21 | for i in range(len(self.days_items)):
22 | completed_tasks += self.days_items[i]["total_completed"]
23 | return completed_tasks
24 |
25 |
26 | def get_daily_completed_tasks(self):
27 | return self.days_items[0]["total_completed"]
28 |
29 |
30 | def get_total_tasks(self):
31 | number_of_tasks = 0
32 | #This is meant as a safeguard against too many Todoist API calls
33 | try:
34 | projects = self.user.get_projects()
35 | for project in projects:
36 | tasks = project.get_tasks()
37 | number_of_tasks += len(tasks)
38 | return number_of_tasks
39 | except:
40 | return 0
41 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/08-bubble-chart/basic-bubble-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 | CanvasJS Example
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/20-range-area-chart/range-area-with-null-data.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
47 |
48 | CanvasJS Example
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/26-some-common-options-across-all-chart-types/chart-with-animation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
43 |
44 | CanvasJS Example
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/13-candlestick-chart/candle-stick-chart-with-rising-color-and-tooltip-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
46 |
47 | CanvasJS Example
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/02-column-chart/multi-series-column-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
57 |
58 | CanvasJS Example
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/09-stacked-column-chart/basic-stacked-column-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
60 |
61 | CanvasJS Example
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/14-ohlc(stock)-chart/basic-ohlc-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
44 |
45 | CanvasJS Example
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/15-step-line-chart/multi-series-step-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
61 |
62 | CanvasJS Example
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/23-stacked-bar-100-chart/basic-stacked-bar-100-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
60 |
61 | CanvasJS Example
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/09-stacked-column-chart/stacked-column-with-total-shown-on-top.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
53 |
54 | CanvasJS Example
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/personal_dashboard/spotify.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import spotipy
3 | import spotipy.util as util
4 | try:
5 | from .personal_info import SPOTIFY
6 | except:
7 | from personal_info import SPOTIFY
8 |
9 |
10 |
11 | #The spotify class has two methods: get_monthly_top_tracks() which returns
12 | # the top 5 tracks for that month, the get_monthly_top_artists() returns the top
13 | # three artists for that month
14 | class Spotify():
15 | def __init__(self):
16 | #This requires a users prompting first time its run, afterwards there will
17 | # be a cached file called .cache-spotifyemail, make sure this cached file
18 | # is pushed to whatever cloud based application otherwise it will break
19 | self.token = util.prompt_for_user_token(SPOTIFY['email'],'user-top-read',client_id=SPOTIFY['client_id'],client_secret=SPOTIFY['client_secret'],redirect_uri=SPOTIFY['redirect_uri'])
20 | self.sp = spotipy.Spotify(auth=self.token)
21 |
22 | def get_monthly_top_tracks(self):
23 | top_tracks = self.sp.current_user_top_tracks(limit=5, time_range='short_term')
24 | track_list = []
25 | for item in top_tracks['items']:
26 | track_name = item["name"]
27 | artist_name = item["artists"][0]["name"]
28 | external_url = item["external_urls"]["spotify"]
29 | track_list.append("{1} by {2}
".format(external_url, track_name, artist_name))
30 | return ''.join(track_list)
31 |
32 | def get_monthly_top_artists(self):
33 | top_artists = self.sp.current_user_top_artists(limit=3, time_range='short_term')
34 | artist_list = []
35 | for item in top_artists['items']:
36 | artist = item['name']
37 | external_url = item['external_urls']['spotify']
38 | artist_list.append("{1}
".format(external_url, artist))
39 | return artist_list
40 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | .fa-icon-rotate(@degrees, @rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
16 | -webkit-transform: rotate(@degrees);
17 | -ms-transform: rotate(@degrees);
18 | transform: rotate(@degrees);
19 | }
20 |
21 | .fa-icon-flip(@horiz, @vert, @rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
23 | -webkit-transform: scale(@horiz, @vert);
24 | -ms-transform: scale(@horiz, @vert);
25 | transform: scale(@horiz, @vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | .sr-only() {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | .sr-only-focusable() {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #personal_info.py
2 | __pycache__/
3 | *.py[cod]
4 | venv
5 | __init__.py
6 | personal_info.py
7 | migrations/
8 | .cache-12al104@queensu.ca
9 | moves_data.pkl
10 | nokia_data.pkl
11 |
12 | # Byte-compiled / optimized / DLL files
13 | __pycache__/
14 | *.py[cod]
15 | *$py.class
16 |
17 | # C extensions
18 | *.so
19 |
20 | # Distribution / packaging
21 | .Python
22 | build/
23 | develop-eggs/
24 | dist/
25 | downloads/
26 | eggs/
27 | .eggs/
28 | lib/
29 | lib64/
30 | parts/
31 | sdist/
32 | var/
33 | wheels/
34 | *.egg-info/
35 | .installed.cfg
36 | *.egg
37 | MANIFEST
38 |
39 | # PyInstaller
40 | # Usually these files are written by a python script from a template
41 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
42 | *.manifest
43 | *.spec
44 |
45 | # Installer logs
46 | pip-log.txt
47 | pip-delete-this-directory.txt
48 |
49 | # Unit test / coverage reports
50 | htmlcov/
51 | .tox/
52 | .coverage
53 | .coverage.*
54 | .cache
55 | nosetests.xml
56 | coverage.xml
57 | *.cover
58 | .hypothesis/
59 |
60 | # Translations
61 | *.mo
62 | *.pot
63 |
64 | # Django stuff:
65 | *.log
66 | .static_storage/
67 | .media/
68 | local_settings.py
69 |
70 | # Flask stuff:
71 | instance/
72 | .webassets-cache
73 |
74 | # Scrapy stuff:
75 | .scrapy
76 |
77 | # Sphinx documentation
78 | docs/_build/
79 |
80 | # PyBuilder
81 | target/
82 |
83 | # Jupyter Notebook
84 | .ipynb_checkpoints
85 |
86 | # pyenv
87 | .python-version
88 |
89 | # celery beat schedule file
90 | celerybeat-schedule
91 |
92 | # SageMath parsed files
93 | *.sage.py
94 |
95 | # Environments
96 | .env
97 | .venv
98 | env/
99 | venv/
100 | ENV/
101 | env.bak/
102 | venv.bak/
103 |
104 | # Spyder project settings
105 | .spyderproject
106 | .spyproject
107 |
108 | # Rope project settings
109 | .ropeproject
110 |
111 | # mkdocs documentation
112 | /site
113 |
114 | # mypy
115 | .mypy_cache/
116 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/font-awesome/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 |
12 | }
13 |
14 | @mixin fa-icon-rotate($degrees, $rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
16 | -webkit-transform: rotate($degrees);
17 | -ms-transform: rotate($degrees);
18 | transform: rotate($degrees);
19 | }
20 |
21 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
23 | -webkit-transform: scale($horiz, $vert);
24 | -ms-transform: scale($horiz, $vert);
25 | transform: scale($horiz, $vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | @mixin sr-only {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | @mixin sr-only-focusable {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/26-some-common-options-across-all-chart-types/hide-and-unhide-data-series-from-legend.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
70 |
71 | CanvasJS Example
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/22-stacked-area-100-chart/stacked-area-100-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
75 |
76 | CanvasJS Example
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/08-bubble-chart/bubble-chart-with-tooltip-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
54 |
55 | CanvasJS Example
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/personal_dashboard/withings.py:
--------------------------------------------------------------------------------
1 | from nokia import NokiaAuth, NokiaApi
2 | import pickle
3 | try:
4 | from .personal_info import WITHINGS_KEYS
5 | except:
6 | from personal_info import WITHINGS_KEYS
7 |
8 | #The withings class opens up the pickle file and saves it as the weight unless
9 | # that file doesn't exist than the user needs to authenticate and save a new pickle
10 | #file
11 | class Withings():
12 | def __init__(self):
13 | try:
14 | with open('personal_dashboard/nokia_data.pkl', 'rb') as pickle_file:
15 | nokia = pickle.load(pickle_file)
16 | self.measures = nokia.get_measures()
17 | measures = nokia.get_measures(limit=1)
18 | self.weight = round(float(measures[0].weight)*2.20462, 2)
19 | pickle_file.close()
20 | except:
21 | auth = NokiaAuth(WITHINGS_KEYS['API_KEY'], WITHINGS_KEYS['API_SECRET'])
22 | authorize_url = auth.get_authorize_url()
23 | print("Go to %s allow the app and copy your oauth_verifier" % authorize_url)
24 | oauth_verifier = input('Please enter your oauth_verifier: ')
25 | creds = auth.get_credentials(oauth_verifier)
26 | client = NokiaApi(creds)
27 | with open('personal_dashboard/nokia_data.pkl', 'wb') as output:
28 | pickle.dump(client, output, pickle.HIGHEST_PROTOCOL)
29 | self.measures = client.get_measures()
30 | measures = client.get_measures(limit=1)
31 | #Convert Kg to Lbs
32 | self.weight = round(float(measures[0].weight)*2.20462, 2)
33 |
34 |
35 |
36 | def get_weight_line_data(self):
37 | weight_data = []
38 | dates = []
39 | for data in self.measures:
40 | if data.weight:
41 | year = str(data.date).split('-')[0]
42 | month = str(data.date).split('-')[1]
43 | day = str(data.date).split('-')[2].split("T")[0]
44 | date = month + "-" + day + "-" + year
45 | dates.append(date)
46 | weight_data.append(round(float(data.weight)*2.20462, 2))
47 | weight_data.reverse()
48 | dates.reverse()
49 | return weight_data, dates
50 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/12-scatter-chart/basic-scatter-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
71 |
72 | CanvasJS Example
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/26-some-common-options-across-all-chart-types/combination-charts.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
86 |
87 | CanvasJS Example
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/10-stacked-bar-chart/basic-stacked-bar-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
76 |
77 | CanvasJS Example
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/13-candlestick-chart/basic-candle-stick-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
55 |
56 | CanvasJS Example
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/19-range-column-chart/range-column-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
75 |
76 | CanvasJS Example
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/01-line-chart/multi-series-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
91 |
92 | CanvasJS Example
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/12-scatter-chart/multi-series-scatter-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
98 |
99 | CanvasJS Example
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/static/css/styles.css:
--------------------------------------------------------------------------------
1 | .canvasjs-chart-credit {
2 | display: none;
3 | }
4 |
5 | .quote, .list {
6 | text-align: center;
7 | padding: 20px;
8 | }
9 |
10 | .data_table {
11 | text-align: center;
12 | margin: auto;
13 | }
14 |
15 |
16 | #loading {
17 | margin:auto;
18 | text-align: center;
19 | }
20 |
21 | div, h6 {
22 | visibility: hidden;
23 | }
24 |
25 | strong {
26 | color: black;
27 | }
28 |
29 | body {
30 | background-color: #000000;
31 | color: #ffffff;
32 | font-family: "arial", Helvetica, Arial, sans-serif;
33 | font-size: 16px;
34 | line-height: 1.5;
35 | padding-bottom: 3.5rem;
36 | padding-top: 3.5rem;
37 | }
38 |
39 | h1, h2, h3, h4, h5, h6 {
40 | font-weight: 300;
41 | }
42 |
43 | canvas {
44 | font-family: "Roboto", Helvetica, Arial, sans-serif;
45 | }
46 |
47 | #quote_author {
48 | color:white;
49 | }
50 |
51 | hr {
52 | border-top: 1px solid #727273;
53 | margin-bottom: 2rem;
54 | margin-top: 2rem;
55 | }
56 |
57 | .align-center {
58 | text-align: center;
59 | }
60 |
61 | #meditation_doughnut, #pomodoro_doughnut, #unproductivity_doughnut {
62 | height: 280px;
63 | margin-top: 1rem;
64 | width: 100%;
65 | }
66 |
67 | #cal-heatmap {
68 | width:50%;
69 | margin: 0 auto;
70 | }
71 |
72 | .container {
73 | margin-bottom: 4%;
74 | }
75 |
76 |
77 | .card-header {
78 | background-color: #37474F;
79 | border-radius: 0 !important;
80 | color: white;
81 | margin-bottom: 0;
82 | padding: 1rem;
83 | }
84 |
85 | .card-block {
86 | border: 1px solid #cccccc;
87 | height: 500px;
88 | }
89 |
90 | .shadow {
91 | box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14),
92 | 0 1px 18px 0 rgba(0, 0, 0, 0.12),
93 | 0 3px 5px -1px rgba(0, 0, 0, 0.2);
94 | }
95 |
96 | #moves_places {
97 | color:black;
98 | }
99 |
100 |
101 |
102 | #loading,
103 | #loading:after {
104 | border-radius: 50%;
105 | width: 10em;
106 | height: 10em;
107 | }
108 | #loading {
109 | margin: 60px auto;
110 | font-size: 10px;
111 | position: relative;
112 | text-indent: -9999em;
113 | border-top: 1.1em solid rgba(255, 255, 255, 0.2);
114 | border-right: 1.1em solid rgba(255, 255, 255, 0.2);
115 | border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
116 | border-left: 1.1em solid #ffffff;
117 | -webkit-transform: translateZ(0);
118 | -ms-transform: translateZ(0);
119 | transform: translateZ(0);
120 | -webkit-animation: load8 1.1s infinite linear;
121 | animation: load8 1.1s infinite linear;
122 | }
123 | @-webkit-keyframes load8 {
124 | 0% {
125 | -webkit-transform: rotate(0deg);
126 | transform: rotate(0deg);
127 | }
128 | 100% {
129 | -webkit-transform: rotate(360deg);
130 | transform: rotate(360deg);
131 | }
132 | }
133 | @keyframes load8 {
134 | 0% {
135 | -webkit-transform: rotate(0deg);
136 | transform: rotate(0deg);
137 | }
138 | 100% {
139 | -webkit-transform: rotate(360deg);
140 | transform: rotate(360deg);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/24-stacked-column-100-chart/stacked-column-100-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
99 |
100 | CanvasJS Example
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/jquery.scrollspeed/jquery.scrollspeed.js:
--------------------------------------------------------------------------------
1 | // Plugin: jQuery.scrollSpeed
2 | // Source: github.com/nathco/jQuery.scrollSpeed
3 | // Author: Nathan Rutzky
4 | // Update: 1.0.2
5 |
6 | (function($) {
7 |
8 | jQuery.scrollSpeed = function(step, speed, easing) {
9 |
10 | var $document = $(document),
11 | $window = $(window),
12 | $body = $('html, body'),
13 | option = easing || 'default',
14 | root = 0,
15 | scroll = false,
16 | scrollY,
17 | scrollX,
18 | view;
19 |
20 | if (window.navigator.msPointerEnabled || ($('#isIE').length > 0) ) // custom modification to detect IE
21 |
22 | return false;
23 |
24 | $window.on('mousewheel DOMMouseScroll', function(e) {
25 |
26 | var deltaY = e.originalEvent.wheelDeltaY,
27 | detail = e.originalEvent.detail;
28 | scrollY = $document.height() > $window.height();
29 | scrollX = $document.width() > $window.width();
30 | scroll = true;
31 |
32 | if (scrollY) {
33 |
34 | view = $window.height();
35 |
36 | if (deltaY < 0 || detail > 0)
37 |
38 | root = (root + view) >= $document.height() ? root : root += step;
39 |
40 | if (deltaY > 0 || detail < 0)
41 |
42 | root = root <= 0 ? 0 : root -= step;
43 |
44 | $body.stop().animate({
45 |
46 | scrollTop: root
47 |
48 | }, speed, option, function() {
49 |
50 | scroll = false;
51 |
52 | });
53 | }
54 |
55 | if (scrollX) {
56 |
57 | view = $window.width();
58 |
59 | if (deltaY < 0 || detail > 0)
60 |
61 | root = (root + view) >= $document.width() ? root : root += step;
62 |
63 | if (deltaY > 0 || detail < 0)
64 |
65 | root = root <= 0 ? 0 : root -= step;
66 |
67 | $body.stop().animate({
68 |
69 | scrollLeft: root
70 |
71 | }, speed, option, function() {
72 |
73 | scroll = false;
74 |
75 | });
76 | }
77 |
78 | return false;
79 |
80 | }).on('scroll', function() {
81 |
82 | if (scrollY && !scroll) root = $window.scrollTop();
83 | if (scrollX && !scroll) root = $window.scrollLeft();
84 |
85 | }).on('resize', function() {
86 |
87 | if (scrollY && !scroll) view = $window.height();
88 | if (scrollX && !scroll) view = $window.width();
89 |
90 | });
91 | };
92 |
93 | jQuery.easing.default = function (x,t,b,c,d) {
94 |
95 | return -c * ((t=t/d-1)*t*t*t - 1) + b;
96 | };
97 |
98 | })(jQuery);
--------------------------------------------------------------------------------
/personal_dashboard/books.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from bs4 import BeautifulSoup
3 | import datetime
4 | try:
5 | from .personal_info import GOODREADS_INFO
6 | except:
7 | from personal_info import GOODREADS_INFO
8 |
9 | class Books():
10 | def __init__(self):
11 | self.goodreads_url = f'https://www.goodreads.com/review/list/{GOODREADS_INFO["user_id"]}.xml?key={GOODREADS_INFO["api_key"]}&v=2&shelf=read&per_page=80&page=1'
12 | self.response = requests.get(self.goodreads_url)
13 | self.soup = BeautifulSoup(self.response.text, 'html.parser')
14 | self.reviews = self.soup.find('reviews')
15 |
16 |
17 | # Returns the past n books you've read
18 | def get_past_n_books(self, number_of_books):
19 | books = []
20 | urls = []
21 | for review in self.reviews.find_all('review'):
22 | for title in review.find('title'):
23 | books.append(title)
24 | for url in review.find('url'):
25 | urls.append(url)
26 | books_and_url = "Recently Read Books:"
27 | for i in range(number_of_books):
28 | books_and_url += f'- {books[i]}
'
29 | books_and_url += "
"
30 | return books_and_url
31 |
32 | # Returns a dict containing your reading history for the past 6 months
33 | def get_past_reading_history(self):
34 | dates = []
35 | data_values = []
36 | month_dict = {'Jan' : 1, 'Feb' : 2, 'Mar' : 3, 'Apr' : 4, 'May' : 5, 'Jun' : 6, 'Jul' : 7, 'Aug' : 8, 'Sep' : 9, 'Oct' : 10, 'Nov' : 11, 'Dec' : 12}
37 | books_dict = {}
38 | seven_months_ago = self.get_n_months_ago(6)
39 | for review in self.reviews.find_all('review'):
40 | for date_read in review.find('date_added'):
41 | month = date_read.split(" ")[1]
42 | year = date_read.split(" ")[5]
43 | date = datetime.date(int(year), month_dict[month], 1)
44 | if date >= seven_months_ago:
45 | date = str(date)
46 | if date in books_dict:
47 | books_dict[date] += 1
48 | else:
49 | books_dict[date] = 1
50 | #If there was a month that I didn't finish a book, I want to set it to 0
51 | for some_month in range(7):
52 | some_month_ago = str(self.get_n_months_ago(some_month))
53 | if some_month_ago not in books_dict:
54 | books_dict[some_month_ago] = 0
55 | sorted_keys = sorted(books_dict.keys())
56 | for key in sorted_keys:
57 | year = key.split("-")[0]
58 | month = key.split("-")[1]
59 | dates.append(f'{month}/{year}')
60 | data_values.append(books_dict[key])
61 | reading_history = [{"label" : "Number of Books Read", "backgroundColor": "#33702a", "data" : data_values}]
62 | return reading_history, dates
63 |
64 |
65 | # Helper function which returns n month ago from now
66 | def get_n_months_ago(self, month):
67 | past_month = datetime.datetime.now().month - month
68 | past_year = datetime.datetime.now().year
69 | if past_month < 1:
70 | past_month = 12 + past_month
71 | past_year = past_year - 1
72 | return datetime.date(past_year, past_month, 1)
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/no-ui-slider/nouislider.min.css:
--------------------------------------------------------------------------------
1 | /*! nouislider - 8.5.1 - 2016-04-24 16:00:30 */
2 |
3 |
4 | .noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-user-select:none;-ms-touch-action:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;user-select:none;-moz-box-sizing:border-box;box-sizing:border-box}.noUi-target{position:relative;direction:ltr}.noUi-base{width:100%;height:100%;position:relative;z-index:1}.noUi-origin{position:absolute;right:0;top:0;left:0;bottom:0}.noUi-handle{position:relative;z-index:1}.noUi-stacking .noUi-handle{z-index:10}.noUi-state-tap .noUi-origin{-webkit-transition:left .3s,top .3s;transition:left .3s,top .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-base,.noUi-handle{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;left:-17px;top:-6px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;left:-6px;top:-17px}.noUi-background{background:#FAFAFA;box-shadow:inset 0 1px 1px #f0f0f0}.noUi-connect{background:#3FB8AF;box-shadow:inset 0 0 3px rgba(51,51,51,.45);-webkit-transition:background 450ms;transition:background 450ms}.noUi-origin{border-radius:2px}.noUi-target{border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-target.noUi-connect{box-shadow:inset 0 0 3px rgba(51,51,51,.45),0 3px 6px -5px #BBB}.noUi-draggable{cursor:w-resize}.noUi-vertical .noUi-draggable{cursor:n-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect,[disabled].noUi-connect{background:#B8B8B8}[disabled] .noUi-handle,[disabled].noUi-origin{cursor:not-allowed}.noUi-pips,.noUi-pips *{-moz-box-sizing:border-box;box-sizing:border-box}.noUi-pips{position:absolute;color:#999}.noUi-value{position:absolute;text-align:center}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{position:absolute;background:#CCC}.noUi-marker-large,.noUi-marker-sub{background:#AAA}.noUi-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.noUi-value-horizontal{-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0)}.noUi-marker-horizontal.noUi-marker{margin-left:-1px;width:2px;height:5px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.noUi-value-vertical{-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0);padding-left:25px}.noUi-marker-vertical.noUi-marker{width:5px;height:2px;margin-top:-1px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{display:block;position:absolute;border:1px solid #D9D9D9;border-radius:3px;background:#fff;padding:5px;text-align:center}.noUi-horizontal .noUi-handle-lower .noUi-tooltip{top:-32px}.noUi-horizontal .noUi-handle-upper .noUi-tooltip{bottom:-32px}.noUi-vertical .noUi-handle-lower .noUi-tooltip{left:120%}.noUi-vertical .noUi-handle-upper .noUi-tooltip{right:120%}
--------------------------------------------------------------------------------
/personal_dashboard/articles.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import datetime
4 | try:
5 | from .personal_info import MEDIUM_USER
6 | except:
7 | from personal_info import MEDIUM_USER
8 |
9 |
10 | class Articles():
11 | def __init__(self):
12 | self.medium_url = f'https://medium.com/@{MEDIUM_USER}/'
13 | self.response = requests.get(self.medium_url + 'latest?format=json')
14 | self.response_dict = json.loads(
15 | self.response.text.split('])}while(1);')[1])
16 | self.posts = self.response_dict['payload']['references']['Post']
17 |
18 |
19 | # Returns the past n articles you've writte
20 | def get_past_n_articles(self, number_of_articles):
21 | titles = []
22 | urls = []
23 | for key in self.posts:
24 | titles.append(self.posts[key]['title'])
25 | urls.append(self.medium_url + self.posts[key]['id'])
26 | titles_and_url = "Recently Written Articles:"
28 | for i in range(number_of_articles):
29 | titles_and_url += f'- {titles[i]}
'
30 | titles_and_url += "
"
31 | return titles_and_url
32 |
33 |
34 | # Returns a dict containing your reading history for the past n months
35 | def get_past_n_month_writing_history(self, months):
36 | dates = []
37 | data_values = []
38 | month_dict = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
39 | 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
40 | article_count_dict = {}
41 | n_months_ago = self.get_n_months_ago(months)
42 | for key in self.posts:
43 | timestamp = int(self.posts[key]['firstPublishedAt']) / 1000
44 | month_published = datetime.datetime.fromtimestamp(timestamp).month
45 | year_published = datetime.datetime.fromtimestamp(timestamp).year
46 | dt = datetime.date(int(year_published), int(month_published), 1)
47 | if dt >= n_months_ago:
48 | dt = str(dt)
49 | if dt in article_count_dict:
50 | article_count_dict[dt] += 1
51 | else:
52 | article_count_dict[dt] = 1
53 | #If there was a month that I didn't finish an article, I want to set it to 0
54 | for some_month in range(7):
55 | some_month_ago = str(self.get_n_months_ago(some_month))
56 | if some_month_ago not in article_count_dict:
57 | article_count_dict[some_month_ago] = 0
58 | sorted_keys = sorted(article_count_dict.keys())
59 | for key in sorted_keys:
60 | year = key.split("-")[0]
61 | month = key.split("-")[1]
62 | dates.append(f'{month}/{year}')
63 | data_values.append(article_count_dict[key])
64 | writing_history = [{"label": "Number of Articles Written",
65 | "backgroundColor": "#33702a", "data": data_values}]
66 | return writing_history, dates
67 |
68 |
69 | # Helper function which returns n month ago from now
70 | def get_n_months_ago(self, month):
71 | past_month = datetime.datetime.now().month - month
72 | past_year = datetime.datetime.now().year
73 | if past_month < 1:
74 | past_month = 12 + past_month
75 | past_year = past_year - 1
76 | return datetime.date(past_year, past_month, 1)
77 |
78 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/22-stacked-area-100-chart/basic-stacked-area-100-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
100 |
101 | CanvasJS Example
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/10-stacked-bar-chart/stacked-bar-chart-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
116 |
117 | CanvasJS Example
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/11-stacked-area-chart/basic -stacked-area-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
100 |
101 | CanvasJS Example
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/web-analytics/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #ffffff;
3 | font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif;
4 | font-size: 14px;
5 | padding-top: 64px;
6 | }
7 |
8 | #header {
9 | background-color: #34495e;
10 | height: 64px;
11 | margin-bottom: 0;
12 | padding: 0;
13 | position: fixed;
14 | }
15 |
16 | #header .container-fluid {
17 | padding: 8px;
18 | }
19 |
20 | #header .navbar-header {
21 | margin: 0;
22 | }
23 |
24 | #header #sidebar-toggle-button {
25 | color: #fff;
26 | cursor: pointer;
27 | display: inline-block;
28 | font-size: 17px;
29 | margin: 0 15px;
30 | padding: 12px 6px;
31 | }
32 |
33 | #header .brand {
34 | display: inline-block;
35 | padding: 12px 16px 12px 0;
36 | }
37 |
38 | #header .brand a {
39 | color: #fff;
40 | font-size: 24px;
41 | line-height: 1;
42 | text-decoration: none;
43 | }
44 |
45 | #sidebar {
46 | background-color: #eceef1;
47 | bottom: 0;
48 | display: block;
49 | left: 0;
50 | overflow-x: hidden;
51 | overflow-y: auto;
52 | padding: 0;
53 | position: fixed;
54 | top: 64px;
55 | width: 264px;
56 | z-index: 1000;
57 | }
58 |
59 | #sidebar > ul {
60 | padding-bottom: 24px;
61 | }
62 |
63 | #sidebar > ul > li {
64 | margin: 0;
65 | }
66 |
67 | #sidebar > ul > li > a {
68 | color: #20252b;
69 | display: block;
70 | padding: 12px 24px;
71 | text-decoration: none;
72 | }
73 |
74 | #sidebar > ul > li > a > span {
75 | font-size: 17px;
76 | font-weight: 500;
77 | margin-left: 17px;
78 | }
79 |
80 | #sidebar > ul > li > a:hover,
81 | #sidebar > ul > li > a.active {
82 | border-right: 4px solid #34495e;
83 | }
84 |
85 |
86 | #sidebar > ul > .divider {
87 | background-color: #ccc;
88 | height: 1px;
89 | margin: 0;
90 | overflow: hidden;
91 | }
92 |
93 | #page-content-wrapper > .container-fluid {
94 | padding-top: 0.75rem;
95 | }
96 |
97 | /*------ sidebar toggle ------*/
98 | .sidebar-toggle {
99 | display: none !important;
100 | }
101 |
102 | .page-content-toggle {
103 | margin-left: inherit !important;
104 | }
105 |
106 | @media (min-width: 1600px) {
107 | #sidebar {
108 | display: none;
109 | }
110 | .sidebar-toggle {
111 | display: block !important;
112 | }
113 | .page-content-toggle {
114 | margin-left: 264px !important;
115 | }
116 | }
117 | /*------ /sidebar toggle ------*/
118 |
119 | /*------ real time page charts ------*/
120 | #users-device-doughnut-chart,
121 | #users-medium-pie-chart,
122 | #users-category-pie-chart,
123 | #page-views-per-second-column-chart,
124 | #page-views-per-minute-column-chart,
125 | #users-state-bar-chart {
126 | height: 300px;
127 | }
128 | /*------ /real time page charts ------*/
129 |
130 | /*------ overview page charts ------*/
131 | #revenue-spline-area-chart,
132 | #annual-revenue-by-category-pie-chart,
133 | #monthly-revenue-by-category-column-chart {
134 | height: 300px;
135 | }
136 |
137 | #visitors-chart,
138 | #users-spline-chart {
139 | height: 320px;
140 | }
141 | /*------ /overview page charts ------*/
142 |
143 | .card {
144 | background-color: inherit;
145 | border: none;
146 | }
147 |
148 | .card-title {
149 | border-bottom: 1px solid;
150 | padding-bottom: 10px;
151 | font-size: 26px;
152 | font-weight: 300;
153 | }
154 |
155 | #revenue-tag, .custom-tag {
156 | background-color: #d9695f;
157 | border-radius: 0;
158 | font-weight: 400;
159 | vertical-align: top;
160 | }
161 |
162 | .custom-tag {
163 | font-size: 100%;
164 | }
165 |
166 | #visitors-chart-back-button {
167 | padding: 0.3rem 0.6rem;
168 | }
169 |
170 | #visitors-chart-tag {
171 | position: absolute;
172 | }
--------------------------------------------------------------------------------
/personal_dashboard/toggl.py:
--------------------------------------------------------------------------------
1 | import requests
2 | try:
3 | from .personal_info import TOGGL_API_TOKEN
4 | except:
5 | from personal_info import TOGGL_API_TOKEN
6 | import base64
7 | import decimal
8 | import time
9 | import math
10 | import datetime as DT
11 |
12 |
13 | #The Toggl class is meant to get the pomodoro sessions using the get_pomodoros method
14 | class Toggl():
15 | def __init__(self):
16 | headers = {
17 | "Authorization": "",
18 | "Content-Type": "application/json",
19 | "Accept": "*/*",
20 | "User-Agent": "python/urllib",
21 | }
22 | authHeader = TOGGL_API_TOKEN + ":" + "api_token"
23 | authHeader = "Basic " + str(base64.b64encode(authHeader.encode()))[2:]
24 | authHeader = authHeader.replace('\'', "")
25 | headers['Authorization'] = authHeader
26 | url = 'https://www.toggl.com/api/v8/time_entries?api_token='+TOGGL_API_TOKEN
27 | self.json = requests.get(url, headers=headers).json()
28 |
29 |
30 | def get_pomodoros(self, dates):
31 | pomodoroDict = {}
32 | for index, time_entry in enumerate(self.json):
33 | end_time = time_entry['start'].split('T')[0]
34 | if end_time in dates:
35 | time_in_hours = time_entry['duration']/60/60
36 | try:
37 | description = time_entry['description']
38 | except:
39 | description = "No description"
40 | if description != 'Pomodoro Break':
41 | if time_in_hours < 0:
42 | epoch_time = int(time.time())
43 | time_in_hours = (epoch_time + time_entry['duration'])/60/60
44 | if description in pomodoroDict:
45 | pomodoroDict[description] += round(time_in_hours, 2)
46 | else:
47 | pomodoroDict[description] = round(time_in_hours, 2)
48 | return pomodoroDict
49 |
50 |
51 | def get_daily_pomodoros(self):
52 | dates = [time.strftime("%Y-%m-%d")]
53 | return self.get_pomodoros(dates)
54 |
55 |
56 | def get_past_seven_days_pomodoros(self):
57 | dates = []
58 | today = DT.date.today()
59 | for i in range(7):
60 | date = today - DT.timedelta(days=i)
61 | date = date.strftime("%Y-%m-%d")
62 | dates.append(date)
63 | return self.get_pomodoros(dates)
64 |
65 | # for use in the create_toggl_bar function in scripts.js
66 | def get_daily_week_view(self):
67 | toggl_data = []
68 | pomodoros = self.get_past_seven_days_pomodoros()
69 | #This is to loop through all the different descriptions in Toggl
70 | for pomodoro in pomodoros:
71 | counter = 6
72 | weekly_data = [pomodoro]
73 | #We loop through a given week to find the times for this specific Toggl description
74 | for i in range(7):
75 | today = DT.date.today()
76 | date = today - DT.timedelta(days=counter)
77 | counter -= 1
78 | date = date.strftime("%Y-%m-%d")
79 | year = date.split('-')[0]
80 | month = date.split('-')[1]
81 | day = date.split('-')[2]
82 | #Here we need to get the pomodoros for that specific day
83 | pomodoros = self.get_pomodoros(date)
84 | for second_pomodoro in pomodoros:
85 | if second_pomodoro == pomodoro:
86 | daily_data = {'year' : year, 'month' : month, 'day' : day, 'value' : pomodoros[pomodoro]}
87 | weekly_data.append(daily_data)
88 | else:
89 | daily_data = {'year': year, 'month': month, 'day': day, 'value': 0}
90 | weekly_data.append(daily_data)
91 | toggl_data.append(weekly_data)
92 | return toggl_data
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/11-stacked-area-chart/stacked-area-chart-with-shared-tooltip.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
127 |
128 | CanvasJS Example
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/14-ohlc(stock)-chart/ohlc-chart-with-tooltip-customization.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
76 |
77 | CanvasJS Example
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/personal_dashboard/meditation.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import requests
3 | from datetime import timedelta
4 | try:
5 | from .personal_info import INSIGHT_MEDITATION_LOGIN
6 | except:
7 | from personal_info import INSIGHT_MEDITATION_LOGIN
8 |
9 |
10 | class Meditation():
11 | '''The meditation class gets meditation data from
12 | insight timer and returns it in a dictionary that maps
13 | the date to the time meditated'''
14 | def __init__(self):
15 | self.insight_csv_url = "https://profile.insighttimer.com/sessions/export"
16 | self.meditation_data = self.get_insight_data()
17 |
18 | def get_insight_data(self):
19 | ''' Retrieves the meditation data in a CSV format from insight timer'''
20 | session = requests.Session()
21 | session.auth = (INSIGHT_MEDITATION_LOGIN['username'], INSIGHT_MEDITATION_LOGIN['password'])
22 | session.post(self.insight_csv_url)
23 | response = session.get(self.insight_csv_url)
24 | # This gets rid of the header and deletes the empty space
25 | return response.text.split("\n")[2:-1]
26 |
27 |
28 | def get_weekly_meditation_data(self):
29 | '''Takes in the response from insight timer CSV and returns
30 | a meditation dictionary containing the dates and times for the past week'''
31 | meditation_dict = {}
32 | dates = []
33 | data_values = []
34 | today = datetime.date.today()
35 | week_ago = today - datetime.timedelta(days=7)
36 | for row in self.meditation_data:
37 | meditation_date = self.get_date(row)
38 | meditation_date_key = row.split(" ")[0]
39 | if meditation_date <= week_ago:
40 | break
41 | meditation_time = row.split(",")[1].split(":")[1]
42 | if meditation_date_key in meditation_dict:
43 | meditation_dict[meditation_date_key] += int(meditation_time)
44 | else:
45 | meditation_dict[meditation_date_key] = int(meditation_time)
46 | # If there was a day with no meditation, the day should be set it to 0
47 | for some_day in range(1, 7):
48 | some_day_ago = str(self.get_n_days_ago(some_day))
49 | if some_day_ago not in meditation_dict:
50 | meditation_dict[some_day_ago] = 0
51 | sorted_keys = sorted(meditation_dict.keys())
52 | for key in sorted_keys:
53 | month = key.split("/")[0]
54 | day = key.split("/")[1]
55 | dates.append(f'{day}/{month}')
56 | data_values.append(meditation_dict[key])
57 | meditation_history = [{"label" : "Minutes Meditated", "backgroundColor": "#33702a", "data" : data_values}]
58 | return meditation_history, dates
59 |
60 |
61 | def get_n_days_ago(self, day):
62 | today = datetime.datetime.now()
63 | days_ago = datetime.timedelta(days = day)
64 | day = today - days_ago
65 | day = str(day).split(" ")[0]
66 | date = day.split("-")
67 | year = date[0]
68 | month = date[1]
69 | day = date[2]
70 | date_formatted = f'{month}/{day}/{year}'
71 | return date_formatted
72 |
73 |
74 | def get_current_meditation_time(self):
75 | '''Takes in the response from insight timer CSV and returns
76 | how much you meditated today.'''
77 | meditation_dict = {}
78 | today = datetime.date.today()
79 | total_meditation = 0
80 | for row in self.meditation_data:
81 | meditation_date = self.get_date(row)
82 | if meditation_date != today:
83 | break
84 | meditation_time = row.split(",")[1].split(":")[1]
85 | total_meditation += int(meditation_time)
86 | return total_meditation
87 |
88 |
89 | def get_date(self, row):
90 | '''Takes in a insight row and returns only the meditation
91 | date in YYYY-MM-DD datetime format'''
92 | date_and_time = row.split(",")[0]
93 | month, day, year = map(int, date_and_time.split(" ")[0].split("/"))
94 | hour, mins, _ = map(int, date_and_time.split(" ")[1].split(":"))
95 | # minus 5 hours to get EST time since insight timer is in UTC
96 | converted_date = datetime.datetime(
97 | year, month, day, hour, mins) - timedelta(hours=5)
98 | # Since we only care about the date, thats the only thing we return
99 | return datetime.date(converted_date.year, converted_date.month, converted_date.day)
100 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/21-range-spline-area-chart/range-spline-area-with-line-chart.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
136 |
137 | CanvasJS Example
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Personal Dashboard
2 | 
3 |
4 | This is a personal dashboard I built to aggregate and visualize all the different tracking services that track my life. The dashboard is updated in real time and can be found at https://qself-dashboard.herokuapp.com/
5 |
6 | Right now it visualizes:
7 | - Time spent online, along with productivtity and unproductivity (Rescuetime)
8 | - Steps and location (Moves)
9 | - Chess (lichess.com)
10 | - Weight (Withings smart scale)
11 | - Pomodoro time (Toggl.com)
12 | - Todo's (Todoist)
13 | - Time spent programming (Wakatime)
14 | - Top artists and songs for the month (Spotify)
15 |
16 | ## Table of Contents
17 |
18 | - [Installation and Setup](#installation)
19 | - [Support](#support)
20 | - [Contributing](#contributing)
21 | - [Licensing](#licensing)
22 |
23 |
24 | ## Installation and Setup
25 |
26 | First make sure you have python3 installed and are using it throughout, since some of the syntax doesn't port over to python2.
27 |
28 | ```sh
29 | git clone https://github.com/Andreilys/personal_dashboard
30 | ```
31 | Install [Postgres](https://www.postgresql.org/download/)
32 | Now, enter your API credentials into personal\_info\_template.py and rename it to personal\_info.py. Run these commands next:
33 |
34 | ```sh
35 | psql
36 | CREATE DATABASE qself_dashboard;
37 | \q
38 | Run python manage.py db init
39 | python manage.py db migrate
40 | python manage.py db upgrade
41 | #you should now be able to run the application
42 | python3 app.py
43 | ```
44 |
45 | You'll now need to give permission to Spotify for the app to access your data (Which will save a .emailCache file) followed by withings (make sure you are just copy+pasting oauth\_verifier and not including oauth\_token) and Moves which should then create permanent pickle files in your personal\_dashboard folder.
46 |
47 | You're done setting it up locally!
48 |
49 | **Setting up on Heroku**
50 | With the application working locally, you might be interested in hosting it on the cloud, I prefer heroku so i'll walk you through instructions on how to set up there. First things first, make sure you register an account on heroku and download their [Heroku Toolbelt](https://devcenter.heroku.com/articles/heroku-cli), afterwards login with heroku login.
51 |
52 | Once logged in run these commands
53 | ```sh
54 | heroku create (your app name)
55 | git remote add pro git@heroku.com:YOUR\_APP\_NAME.git
56 | git add personal\_dashboard/personal\_info.py -f
57 | git add migrations -f
58 | git add nokia\_data.pkl -f
59 | git add moves\_data.pkl -f
60 | git commit -m "adding personal info and migrations folder" (may need to login to github for this)
61 | git push pro master
62 | heroku config:set APP\_SETTINGS=config.ProductionConfig
63 | heroku addons:create heroku-postgresql:hobby-dev --app (YOUR\_APP\_NAME)
64 | heroku run python manage.py db upgrade --app (YOUR\_APP\_NAME)
65 | ```
66 |
67 | Thats it! The other thing you should consider doing is setting the timezone of your heroku app so that everything is in sync, you can do this with the following command (Substituting the timezone with your own)
68 |
69 | ```sh
70 | heroku config:add TZ="America/Los\_Angeles"
71 | ```
72 | ## Support
73 |
74 | Please [open an issue](https://github.com/Andreilys/personal_dashboard/issues/new) for support.
75 |
76 |
77 | ## Contributing
78 |
79 | Please contribute using [Github Flow](https://guides.github.com/introduction/flow/). Create a branch, add commits, and [open a pull request](https://github.com/andreilys/personal_dashboard/compare).
80 |
81 | ## Licensing
82 |
83 | CanvasJS is a commercial product and commercial usage of CanvasJS requires you to purchase a license. Without a commercial license, you can use it for evaluation purposes only. Please refer to the following link for further details: https://canvasjs.com
84 |
85 | Copyright (c) 2017, Andrei Lyskov
86 |
87 | Permission is hereby granted, free of charge, to any person obtaining a copy
88 | of this software and associated documentation files (the "Software"), to deal
89 | in the Software without restriction, including without limitation the rights
90 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91 | copies of the Software, and to permit persons to whom the Software is
92 | furnished to do so, subject to the following conditions:
93 |
94 | The above copyright notice and this permission notice shall be included in all
95 | copies or substantial portions of the Software.
96 |
97 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
98 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
100 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
101 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
102 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
103 | SOFTWARE.
104 |
--------------------------------------------------------------------------------
/static/js/canvasjs/examples/23-stacked-bar-100-chart/stacked-bar-100-with-index-label.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
179 |
180 | CanvasJS Example
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/static/js/canvasjs/assets/economy-dashboard/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-image: url("images/paper-texture.png");
3 | }
4 | blockquote {
5 | border-left: 2px solid #065f66;
6 | margin-left: 5px;
7 | padding-left: 10px;
8 | }
9 | blockquote p {
10 | display: inline;
11 | }
12 | .author {
13 | color: #8793A4;
14 | font-family: 'Bookman Old Style', serif;
15 | font-size: 20px;
16 | }
17 | .author::before {
18 | content: '\2014 \00A0';
19 | }
20 | .header {
21 | padding-top: 15px;
22 | }
23 | .heading {
24 | color: #065f66;
25 | font-family: Garamond, serif;
26 | font-size: 50px;
27 | font-weight: 900;
28 | }
29 | .quotes {
30 | font-size: 23px;
31 | margin-left: 10px;
32 | }
33 | .quotes-size {
34 | color: #065f66;
35 | font-size: 27px !important;
36 | }
37 | .chart-title {
38 | color: #065F66;
39 | font-size: 25px;
40 | font-weight: 600;
41 | height: 40px;
42 | margin-left: 15px;
43 | margin-bottom: 35px;
44 | padding: 5px;
45 | text-align: left;
46 | }
47 | .life-expec-chart-info {
48 | padding-top: 10px;
49 | top: 25px;
50 | }
51 | .play-btn {
52 | cursor: pointer;
53 | font-size: 30px !important;
54 | margin-left: 40%;
55 | }
56 | .pause-btn {
57 | cursor: pointer;
58 | font-size: 30px !important;
59 | margin-left: 40%;
60 | }
61 | .noUi-connect {
62 | background: #c0392b;
63 | }
64 | .noUi-handle {
65 | border: 0px;
66 | box-shadow: inset 0 0 0px #c0392b,inset 0 0px 7px #c0392b,0 0px 6px -3px #c0392b;
67 | }
68 | .noUi-base {
69 | cursor: pointer;
70 | }
71 | .noUi-horizontal .noUi-handle {
72 | border-radius: 50%;
73 | background-color: #c0392b;
74 | cursor: pointer;
75 | height: 24px;
76 | left: -12px;
77 | top: -9px;
78 | width: 24px;
79 | }
80 | .noUi-handle::after, .noUi-handle::before {
81 | display: none;
82 | }
83 | .noUi-value-sub {
84 | color: #686868;
85 | font-size: 11;
86 | }
87 | .noUi-value.noUi-value-horizontal.noUi-value-sub {
88 | cursor: pointer;
89 | }
90 | .noUi-pips {
91 | color: #686868;
92 | }
93 | #year-slider {
94 | height: 8px;
95 | }
96 | .slider{
97 | margin-left: 0%;
98 | margin-top: 12px;
99 | }
100 | .population-chart-info{
101 | padding-top: 10px;
102 | top: 80px;
103 | }
104 | .chart-info-description {
105 | color: #878787;
106 | font-size: 18px;
107 | text-align: left;
108 | }
109 | .economy-definition {
110 | color: #878787;
111 | display: block;
112 | font-size: 23px;
113 | margin-bottom: 0px;
114 | margin-top: 10px;
115 | }
116 | .remove-population-charts-padding{
117 | padding-left: 0px;
118 | padding-right: 0px;
119 | }
120 | .population-charts-title{
121 | color: #065F66;
122 | font-size: 25px;
123 | font-weight: 600;
124 | height: 40px;
125 | margin-bottom: 35px;
126 | padding: 5px;
127 | text-align: left;
128 | }
129 | @media (min-width: 1020px) {
130 | .author {
131 | color: #8793A4;
132 | font-family: 'Bookman Old Style', serif;
133 | font-size: 20px;
134 | margin-left: 786px;
135 | }
136 | }
137 | @media (max-width: 885px) {
138 | .economy-definition {
139 | color: #878787;
140 | display: block;
141 | font-size: 20px;
142 | margin-bottom: 0px;
143 | margin-top: 10px;
144 | }
145 | }
146 | @media (min-width: 861px) and (max-width: 1018px) {
147 | .author {
148 | color: #8793A4;
149 | font-family: 'Bookman Old Style', serif;
150 | font-size: 18px;
151 | margin-left: 80%;
152 | }
153 | }
154 | @media (min-width: 547px) and (max-width: 880px) {
155 | .author {
156 | color: #8793A4;
157 | font-family: 'Bookman Old Style', serif;
158 | font-size: 18px;
159 | margin-left: 70%;
160 | }
161 | }
162 | @media (min-width: 359px) and (max-width: 547px) {
163 | .author {
164 | color: #8793A4;
165 | font-family: 'Bookman Old Style', serif;
166 | font-size: 18px;
167 | margin-left: 50%;
168 | }
169 | }
170 | @media (max-width: 359px) {
171 | .author {
172 | color: #8793A4;
173 | font-family: 'Bookman Old Style', serif;
174 | font-size: 18px;
175 | margin-left: 30%;
176 | }
177 | .heading {
178 | color: #065f66;
179 | font-family: Garamond, serif;
180 | font-size: 45px;
181 | font-weight: 900;
182 | line-height: 52px;
183 | }
184 | }
185 | @media (max-width: 509px) {
186 | .heading {
187 | color: #065f66;
188 | font-family: Garamond, serif;
189 | font-size: 45px;
190 | font-weight: 900;
191 | line-height: 52px;
192 | }
193 | }
194 | @media (max-width: 544px) {
195 | .slider {
196 | margin-left: 5%;
197 | margin-top: 12px;
198 | }
199 | }
200 | @media (min-width:701px) {
201 | #GDP-per-capita-bubble-chart {
202 | height: 500px;
203 | }
204 | }
205 | @media (max-width:700px) and (min-width: 501px) {
206 | #GDP-per-capita-bubble-chart {
207 | height: 400px;
208 | }
209 | }
210 | @media (max-width:500px) {
211 | #GDP-per-capita-bubble-chart {
212 | height: 300px;
213 | }
214 | }
215 | @media (max-width: 600px) {
216 | #population-line-chart {
217 | height: 300px;
218 | }
219 | #working-population-line-chart {
220 | height: 300px;
221 | }
222 | #merchandise-imports-exports-column-chart {
223 | height: 300px;
224 | }
225 | }
226 | @media (min-width: 601px) {
227 | #population-line-chart {
228 | height: 400px;
229 | }
230 | #working-population-line-chart {
231 | height: 400px;
232 | }
233 | }
234 | @media (max-width: 991px) and (min-width: 601px) {
235 | #merchandise-imports-exports-column-chart {
236 | height: 400px;
237 | }
238 | }
239 | @media (min-width: 992px) {
240 | #merchandise-imports-exports-column-chart {
241 | height: 500px;
242 | }
243 | }
--------------------------------------------------------------------------------
/personal_dashboard/moves.py:
--------------------------------------------------------------------------------
1 | import requests
2 | try:
3 | from .personal_info import MOVES_KEYS
4 | except:
5 | from personal_info import MOVES_KEYS
6 | import pickle
7 | from statistics import mean
8 | from datetime import datetime
9 |
10 | #The moves class has the following methods: get_current_days_steps() which
11 | # returns the current days steps, get_average_past_seven_steps() which takes
12 | # the 7 past days of steps and returns the average. The other methods are mostly
13 | #helper methods
14 | class Moves():
15 | def __init__(self):
16 | self.client_id = MOVES_KEYS['client_id']
17 | self.client_secret = MOVES_KEYS['client_secret']
18 | self.redirect_uri = MOVES_KEYS['redirect_uri']
19 | self.auth_url = 'https://api.moves-app.com/oauth/v1/'
20 | self.base_url = 'https://api.moves-app.com/api/1.1/user/'
21 | try:
22 | with open('personal_dashboard/moves_data.pkl', 'rb') as pickle_file:
23 | moves = pickle.load(pickle_file)
24 | self.refresh_token = moves['refresh_token']
25 | self.access_token = moves['access_token']
26 | self.get_access_token()
27 | except:
28 | request_url = "https://api.moves-app.com/oauth/v1/authorize?response_type=code&client_id=" + MOVES_KEYS['client_id'] +"&scope=activity+location"
29 | print("Please go to this URL and authorize: " + request_url)
30 | auth_code = input("What is the authorization code in the code= slug? ")
31 | post_request = requests.post(self.auth_url + "access_token?grant_type=authorization_code&code=" + auth_code + "&client_id=" + self.client_id +
32 | "&client_secret=" + self.client_secret + "&redirect_uri="+ self.redirect_uri).json()
33 | self.access_token = post_request['access_token']
34 | self.refresh_token = post_request['refresh_token']
35 | moves = {"access_token" : self.access_token, "refresh_token" : self.refresh_token}
36 | with open('personal_dashboard/moves_data.pkl', 'wb') as output:
37 | pickle.dump(moves, output, pickle.HIGHEST_PROTOCOL)
38 |
39 |
40 | def get_access_token(self):
41 | data = requests.get(self.auth_url + 'tokeninfo?access_token=' + self.access_token)
42 | if data.status_code != 200:
43 | refresh = requests.post(self.auth_url + "access_token?grant_type=refresh_token&refresh_token=" + self.access_token + "&client_id=" + self.client_id + "&client_secret=" + client_secret).json()
44 | self.refresh_token = refresh["refresh_token"]
45 | self.access_token = refresh["access_token"]
46 |
47 |
48 | def get_current_days_steps(self):
49 | #This is meant as a catch in case no steps have been recorded today
50 | try:
51 | current_days_steps = requests.get(self.base_url + 'summary/daily?pastDays=1&access_token=' + self.access_token).json()
52 | step_count = 0
53 | for i in range(len(current_days_steps[0]["summary"])):
54 | try:
55 | step_count += current_days_steps[0]["summary"][i]["steps"]
56 | except:
57 | pass
58 | return step_count
59 | except Exception as e:
60 | return 0
61 |
62 |
63 | def get_past_seven_days_steps(self):
64 | past_seven_days_steps = requests.get(self.base_url + 'summary/daily?pastDays=8&access_token=' + self.access_token).json()
65 | past_seven_days_arr = []
66 | # Minus one to only look at the past 7 days instead of including the current as well
67 | for index in range(len(past_seven_days_steps) - 1):
68 | try:
69 | day_object_length = len(past_seven_days_steps[index]["summary"])
70 | except:
71 | day_object_length = 0
72 | for i in range(day_object_length):
73 | try:
74 | past_seven_days_arr.append(past_seven_days_steps[index]["summary"][i]["steps"])
75 | except:
76 | past_seven_days_arr.append(0)
77 | return past_seven_days_arr
78 |
79 |
80 | def get_average_past_seven_steps(self):
81 | seven_days_steps_arr = self.get_past_seven_days_steps()
82 | try:
83 | average = round(mean(seven_days_steps_arr))
84 | except:
85 | average = 0
86 | return average
87 |
88 | #Turn this method into a visualizaton for map
89 | def get_past_seven_days_places(self):
90 | past_seven_days_places = requests.get(self.base_url + 'places/daily?pastDays=7&access_token=' + self.access_token)
91 | past_seven_days_places_json = past_seven_days_places.json()
92 | # first 0 is for the length of places, second 0 is for length of segments
93 | past_seven_days_places_set = set()
94 | for i in range(len(past_seven_days_places_json)):
95 | try:
96 | segment_length = len(past_seven_days_places_json[i]['segments'])
97 | except:
98 | segment_length = 0
99 | for j in range(segment_length):
100 | try:
101 | past_seven_days_places_set.add(past_seven_days_places_json[i]['segments'][j]['place']['name'])
102 | except:
103 | continue
104 | return ', '.join(past_seven_days_places_set)
105 |
106 | #This function is used to return dates and a formatted list containing dictionaries
107 | # for use to create the steps_bar
108 | def get_daily_week_view(self):
109 | daily_steps_array = []
110 | average_steps_array = []
111 | avg = self.get_average_past_seven_steps()
112 | #fill array with 7 values of average
113 | for i in range(7):
114 | average_steps_array.append(avg)
115 | past_seven_days_steps = requests.get(self.base_url + 'summary/daily?pastDays=7&access_token=' + self.access_token).json()
116 | for steps in past_seven_days_steps:
117 | try:
118 | daily_steps_array.append(steps['summary'][0]['steps'])
119 | except:
120 | daily_steps_array.append(0)
121 | steps_data = [{"label" : "Daily Steps", "backgroundColor": "#33702a", "data" : daily_steps_array},
122 | {"label" : "Average Steps", "backgroundColor": "#b30000", "data" : average_steps_array}]
123 | return steps_data
124 |
--------------------------------------------------------------------------------
/personal_dashboard/rescuetime.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from time import strftime
3 | try:
4 | from .personal_info import RESCUETIME_API_KEY
5 | except:
6 | from personal_info import RESCUETIME_API_KEY
7 | import datetime as DT
8 |
9 | #This rescuetime class interacts with the rescuetime API allowing it to pull current day and weekly data
10 | # The methods that are used are the get_current_days_data() which returns the
11 | # hours of productive, unproductive hours and the top three sources and get_past_seven_days_data()
12 | # which returns
13 | class RescueTime:
14 | def __init__(self):
15 | self.key = RESCUETIME_API_KEY
16 |
17 | #This method returns a dictionary containing the top three contributing sources to rescuetime,
18 | # productive minutes and unproductive minutes spent up until now
19 |
20 | def get_current_days_data(self):
21 | try:
22 | response = requests.get(
23 | "https://www.rescuetime.com/anapi/data?key={0}&format=json".format(RESCUETIME_API_KEY))
24 | if response.status_code == 502:
25 | daily_data = {"productive_hours": "NULL",
26 | "unproductive_hours": "NULL", "top_three_sources": "NULL"}
27 | return daily_data
28 | json = response.json()["rows"]
29 | # In the event that theres currently no daily data, return 0
30 | except:
31 | daily_data = {"productive_hours": 0,
32 | "unproductive_hours": 0, "top_three_sources": None}
33 | return daily_data
34 | top_three_sources = []
35 | productive_hours = 0
36 | unproductive_hours = 0
37 | for index, data in enumerate(json):
38 | if index < 3:
39 | top_three_sources.append(
40 | str(data[3]).capitalize() + " - " + str(round(data[1]/60/60, 2)))
41 | if data[5] > 0:
42 | productive_hours += data[1]/60/60
43 | elif data[5] < 0:
44 | unproductive_hours += data[1]/60/60
45 | productive_hours = round(productive_hours, 2)
46 | unproductive_hours = round(unproductive_hours, 2)
47 | daily_data = {"productive_hours": productive_hours, "unproductive_hours":
48 | unproductive_hours, "top_three_sources": ", ".join(top_three_sources)}
49 | return daily_data
50 |
51 | # This method is a helper method because the request get method occasionally throews
52 | # an error by returning a None object
53 |
54 | def get_weekly_data(self):
55 | connected = False
56 | while not connected:
57 | try:
58 | today = DT.date.today()
59 | week_ago = today - DT.timedelta(days=7)
60 | response = requests.get("https://www.rescuetime.com/anapi/data?key={0}&perspective=rank&interval=week&restrict_begin={1}&restrict_end={2}&format=json".format(
61 | RESCUETIME_API_KEY, str(week_ago), str(today)))
62 | if response.status_code == 200:
63 | connected = True
64 | except:
65 | pass
66 | return response.json()["rows"]
67 |
68 | #This method returns a dictionary containing the top five contributing sources to rescuetime,
69 | # productive hours and unproductive hours in the last 7 days
70 |
71 | def get_past_seven_days_data(self):
72 | json = self.get_weekly_data()
73 | #This is meant as a safeguard in case resucetime has no weekly data
74 | if json == 0:
75 | weekly_data = {"productive_hours": 0,
76 | "unproductive_hours": 0, "top_five_sources": "None"}
77 | top_five_sources = []
78 | productive_hours = 0
79 | unproductive_hours = 0
80 | for index, data in enumerate(json):
81 | #Grab the first 5 sources since its sorted by ascending order in terms of hours
82 | if index < 5:
83 | top_five_sources.append(
84 | str(data[3]).capitalize() + " - " + str(round(data[1]/60/60, 2)))
85 | if data[5] > 0:
86 | productive_hours += data[1]/60/60
87 | elif data[5] < 0:
88 | unproductive_hours += data[1]/60/60
89 | productive_hours = round(productive_hours, 2)
90 | unproductive_hours = round(unproductive_hours, 2)
91 | weekly_data = {"productive_hours": productive_hours,
92 | "unproductive_hours": unproductive_hours, "top_five_sources": ", ".join(top_five_sources)}
93 | return weekly_data
94 |
95 |
96 | def get_rescuetime_data(self, date):
97 | today = DT.date.today()
98 | date = today - DT.timedelta(days=date)
99 | connected = False
100 | while not connected:
101 | try:
102 | response = requests.get(
103 | "https://www.rescuetime.com/anapi/data?key={0}&perspective=rank&interval=week&restrict_begin={1}&restrict_end={2}&format=json".format(RESCUETIME_API_KEY, str(date), str(date)))
104 | if response.status_code == 200:
105 | connected = True
106 | except:
107 | pass
108 | return date, response.json()["rows"]
109 |
110 | #This function is used to return dates and a formatted list containing dictionaries
111 | # for use in the create_rescuetime_bar function in scripts.js
112 |
113 | def get_daily_week_view(self):
114 | dates = []
115 | productive_array_values = []
116 | unproductive_array_values = []
117 | dates = []
118 | for i in range(1, 8):
119 | today = DT.date.today()
120 | date = today - DT.timedelta(days=i)
121 | dates.append(str(date))
122 | daily_feed_json = requests.get(
123 | "https://www.rescuetime.com/anapi/daily_summary_feed?key={0}&format=json".format(RESCUETIME_API_KEY)).json()
124 | for day in daily_feed_json:
125 | if day['date'] in dates:
126 | productive_array_values.append(day['all_productive_hours'])
127 | unproductive_array_values.append(day['all_distracting_hours'])
128 | # We need to reverse because otherwise the dates will be out of order on the graph
129 | productive_array_values.reverse()
130 | unproductive_array_values.reverse()
131 | rescuetime_data = [{"label": "Productive Hours", "backgroundColor": "#33702a", "data": productive_array_values},
132 | {"label": "Unproductive Hours", "backgroundColor": "#b30000", "data": unproductive_array_values}]
133 | dates = ["-".join(date.split("-")[1:]) for date in dates]
134 | dates.reverse()
135 | return rescuetime_data, dates
136 |
--------------------------------------------------------------------------------