internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: getredash/redash

Issue:
Query execution fails with Google Apps accounts having non-ASCII characters in name
If the account used for Google Apps authentication has non-ASCII characters (ä in this case), execution of queries fails against Amazon Redshift datasource.

[2015-06-05 11:36:13,520][PID:7502][INFO][root] [Manager] Metadata: [{'Username': u'Raimo J\xe4rvenp\xe4\xe4', 'Query ID': 25}]
[2015-06-05 11:36:13,520][PID:7502][INFO][root] [Manager][a2a8974a74cfcb958afc2f843f9f896b] Found existing job: ed40d887-8dae-4e2d-a3a4-439bfb4f01a6
[2015-06-05 11:36:13,521][PID:7502][INFO][root] [a2a8974a74cfcb958afc2f843f9f896b] job found is ready (FAILURE), removing lock



Discussion:
I think I fixed this in the last build. I will make sure and let you know.
On Jun 5, 2015 3:00 PM, "Jari Korkiakoski" notifications@github.com wrote:

> If the account used for Google Apps authentication has non-ASCII
> characters (ä in this case), execution of queries fails against Amazon
> Redshift datasource.
> 
> [2015-06-05 11:36:13,520][PID:7502][INFO][root] [Manager] Metadata:
> [{'Username': u'Raimo J\xe4rvenp\xe4\xe4', 'Query ID': 25}]
> [2015-06-05 11:36:13,520][PID:7502][INFO][root]
> [Manager][a2a8974a74cfcb958afc2f843f9f896b] Found existing job:
> ed40d887-8dae-4e2d-a3a4-439bfb4f01a6
> [2015-06-05 11:36:13,521][PID:7502][INFO][root]
> [a2a8974a74cfcb958afc2f843f9f896b] job found is ready (FAILURE), removing
> lock
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/EverythingMe/redash/issues/444.


Resolving patch:
diff --git a/redash/tasks.py b/redash/tasks.py
--- a/redash/tasks.py
+++ b/redash/tasks.py
@@ -252,9 +252,9 @@ def execute_query(self, query, data_source_id, metadata):
         metadata['Query Hash'] = query_hash
         metadata['Queue'] = self.request.delivery_info['routing_key']
 
-        annotation = ", ".join(["{}: {}".format(k, v) for k, v in metadata.iteritems()])
+        annotation = u", ".join([u"{}: {}".format(k, v) for k, v in metadata.iteritems()])
 
-        logging.debug("Annotation: %s", annotation)
+        logging.debug(u"Annotation: %s", annotation)
 
         annotated_query = u"/* {} */ {}".format(annotation, query)
     else:


Test patch:
Repository: getredash/redash

Issue:
Error running query: datetime.time(13, 52, 27) is not JSON serializable
My table schema:

``` sql
CREATE TABLE F_entrances (
  id SERIAL PRIMARY KEY,
  timeOfEntrance time,
  customerId int REFERENCES D_customers
);
```

(and yes, I committed the horrible sin of camel_case vs underScore.  I'll be fixing that soonish)

The query

``` sql
SELECT
timeofentrance
FROM F_entrances
```

Gives me the error `Error running query: datetime.time(13, 52, 27) is not JSON serializable`.  I worked around it with `to_char` but this seems to be a problem at the [Python layer](http://stackoverflow.com/a/11875813/1216976).



Discussion:
It's definitely is. What datasource type are you using?

Ok, I believe I know where the problem is. Expect a fix tomorrow.

On Sunday, June 28, 2015, Randall Koutnik notifications@github.com wrote:

> My table schema:
> 
> CREATE TABLE F_entrances (
>   id SERIAL PRIMARY KEY,
>   timeOfEntrance time,
>   customerId int REFERENCES D_customers
> );
> 
> (and yes, I committed the horrible sin of camel_case vs underScore. I'll
> be fixing that soonish)
> 
> The query
> 
> SELECT
> timeofentranceFROM F_entrances
> 
> Gives me the error Error running query: datetime.time(13, 52, 27) is not
> JSON serializable. I worked around it with to_char but this seems to be a
> problem at the Python layer http://stackoverflow.com/a/11875813/1216976.
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/EverythingMe/redash/issues/463.

I'm using postgres here.  Thanks for the quick response!


Resolving patch:
diff --git a/redash/utils.py b/redash/utils.py
--- a/redash/utils.py
+++ b/redash/utils.py
@@ -95,7 +95,7 @@ def default(self, o):
         if isinstance(o, decimal.Decimal):
             return float(o)
 
-        if isinstance(o, datetime.date):
+        if isinstance(o, (datetime.date, datetime.time, datetime.timedelta)):
             return o.isoformat()
             
         super(JSONEncoder, self).default(o)


Test patch:
Repository: getredash/redash

Issue:
CLI add new BigQuery datasource - Service Account is actually "Email" Service Account
Adding a new BigQuery datasource the CLI asks me about the service account:

![redash_cli_capture](https://cloud.githubusercontent.com/assets/755254/8698815/7603be02-2ad7-11e5-967e-610d5f32b766.png)

I typed the "Client ID", when actually we need to provide the "Email address"



Discussion:

Resolving patch:
diff --git a/redash/query_runner/big_query.py b/redash/query_runner/big_query.py
--- a/redash/query_runner/big_query.py
+++ b/redash/query_runner/big_query.py
@@ -91,7 +91,7 @@ def configuration_schema(cls):
             'properties': {
                 'serviceAccount': {
                     'type': 'string',
-                    'title': 'Service Account'
+                    'title': 'Service Account Email address'
                 },
                 'projectId': {
                     'type': 'string',
@@ -201,4 +201,4 @@ def _get_bigquery_service(self):
 
 
 register(BigQuery)
-register(BigQueryGCE)
\ No newline at end of file
+register(BigQueryGCE)


Test patch:
Repository: getredash/redash

Issue:
Cannot delete dashboard from home page
On the home page, clicking the "X" next to a dashboard brings up the "are you sure" alert, but clicking OK results in the dashboard not being deleted. The title disappears, but if you reload the page the dashboard is still there.

Version 0.7.1+b1015



Discussion:
It's a bug in the new code that generates the recent dashboards list, it doesn't filter out the archived dashboards. I got aware of it shortly before going on vacation, and I'll fix it when I'm back. Sorry about the confusion.

Once this is fixed, all the dashboards you archived (deleted) will be removed from the list on the homepage.


Resolving patch:
diff --git a/redash/controllers.py b/redash/controllers.py
--- a/redash/controllers.py
+++ b/redash/controllers.py
@@ -307,6 +307,8 @@ def delete(self, dashboard_slug):
         dashboard.is_archived = True
         dashboard.save()
 
+        return dashboard.to_dict(with_widgets=True)
+
 api.add_resource(DashboardListAPI, '/api/dashboards', endpoint='dashboards')
 api.add_resource(DashboardRecentAPI, '/api/dashboards/recent', endpoint='recent_dashboards')
 api.add_resource(DashboardAPI, '/api/dashboards/<dashboard_slug>', endpoint='dashboard')
diff --git a/redash/models.py b/redash/models.py
--- a/redash/models.py
+++ b/redash/models.py
@@ -700,6 +700,7 @@ def to_dict(self, with_widgets=False):
             'layout': layout,
             'dashboard_filters_enabled': self.dashboard_filters_enabled,
             'widgets': widgets_layout,
+            'is_archived': self.is_archived,
             'updated_at': self.updated_at,
             'created_at': self.created_at
         }
@@ -715,6 +716,7 @@ def recent(cls, user_id=None, limit=20):
             where(Event.action << ('edit', 'view')).\
             where(~(Event.object_id >> None)). \
             where(Event.object_type == 'dashboard'). \
+            where(Dashboard.is_archived == False). \
             group_by(Event.object_id, Dashboard.id). \
             order_by(peewee.SQL("count(0) desc"))
 


Test patch:
Repository: getredash/redash

Issue:
API keys should be supported in the HTTP headers
Currently it seems that all API calls must include the `api_key` in the query string. Ideally the HTTP headers could also be used (e.g. `Authorization: Key XXXX` or `X-Api-Key`) so that Web server logs don't log the API key in the clear.



Discussion:
Good idea, it just a matter of updating this function:
https://github.com/EverythingMe/redash/blob/master/redash/authentication.py#L71 to read the value from query string or headers.

+1


Resolving patch:
diff --git a/redash/authentication.py b/redash/authentication.py
--- a/redash/authentication.py
+++ b/redash/authentication.py
@@ -52,6 +52,7 @@ def hmac_load_user_from_request(request):
 
     return None
 
+
 def get_user_from_api_key(api_key, query_id):
     if not api_key:
         return None
@@ -67,8 +68,19 @@ def get_user_from_api_key(api_key, query_id):
 
     return user
 
-def api_key_load_user_from_request(request):
+
+def get_api_key_from_request(request):
     api_key = request.args.get('api_key', None)
+
+    if api_key is None and request.headers.get('Authorization'):
+        auth_header = request.headers.get('Authorization')
+        api_key = auth_header.replace('Key ', '', 1)
+
+    return api_key
+
+
+def api_key_load_user_from_request(request):
+    api_key = get_api_key_from_request(request)
     query_id = request.view_args.get('query_id', None)
 
     user = get_user_from_api_key(api_key, query_id)


Test patch:
diff --git a/tests/test_authentication.py b/tests/test_authentication.py
--- a/tests/test_authentication.py
+++ b/tests/test_authentication.py
@@ -44,6 +44,17 @@ def test_user_api_key(self):
             rv = c.get('/api/queries/', query_string={'api_key': user.api_key})
             self.assertEqual(user.id, api_key_load_user_from_request(request).id)
 
+    def test_api_key_header(self):
+        with app.test_client() as c:
+            rv = c.get('/api/queries/{}'.format(self.query.id), headers={'Authorization': "Key {}".format(self.api_key)})
+            self.assertIsNotNone(api_key_load_user_from_request(request))
+
+    def test_api_key_header_with_wrong_key(self):
+        with app.test_client() as c:
+            rv = c.get('/api/queries/{}'.format(self.query.id), headers={'Authorization': "Key oops"})
+            self.assertIsNone(api_key_load_user_from_request(request))
+
+
 class TestHMACAuthentication(BaseTestCase):
     #
     # This is a bad way to write these tests, but the way Flask works doesn't make it easy to write them properly...
Repository: getredash/redash

Issue:
config request - cleanup_query_results
The cleanup cron is great because it reduces size of redash database. This also allows for smaller quicker backups of its data. If possible, someone can add in a little configuration?

In tasks.py, make it configurable to set a value instead of hardcoded 100. For example, I might want 1000 here:

```
    unused_query_results = models.QueryResult.unused().limit(100)
```

And in models.py, make it configurable on date range instead of hardcoded week_ago. For example, I might only want 1 day here:

```
 week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
```



Discussion:

Resolving patch:
diff --git a/redash/models.py b/redash/models.py
--- a/redash/models.py
+++ b/redash/models.py
@@ -369,10 +369,10 @@ def to_dict(self):
         }
 
     @classmethod
-    def unused(cls):
-        week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
+    def unused(cls, days=7):
+        age_threshold = datetime.datetime.now() - datetime.timedelta(days=days)
 
-        unused_results = cls.select().where(Query.id == None, cls.retrieved_at < week_ago)\
+        unused_results = cls.select().where(Query.id == None, cls.retrieved_at < age_threshold)\
             .join(Query, join_type=peewee.JOIN_LEFT_OUTER)
 
         return unused_results
diff --git a/redash/settings.py b/redash/settings.py
--- a/redash/settings.py
+++ b/redash/settings.py
@@ -69,6 +69,8 @@ def all_settings():
 
 # The following enables periodic job (every 5 minutes) of removing unused query results.
 QUERY_RESULTS_CLEANUP_ENABLED = parse_boolean(os.environ.get("REDASH_QUERY_RESULTS_CLEANUP_ENABLED", "true"))
+QUERY_RESULTS_CLEANUP_COUNT = int(os.environ.get("REDASH_QUERY_RESULTS_CLEANUP_COUNT", "100"))
+QUERY_RESULTS_CLEANUP_MAX_AGE = int(os.environ.get("REDASH_QUERY_RESULTS_CLEANUP_MAX_AGE", "7"))
 
 AUTH_TYPE = os.environ.get("REDASH_AUTH_TYPE", "api_key")
 PASSWORD_LOGIN_ENABLED = parse_boolean(os.environ.get("REDASH_PASSWORD_LOGIN_ENABLED", "true"))
diff --git a/redash/tasks.py b/redash/tasks.py
--- a/redash/tasks.py
+++ b/redash/tasks.py
@@ -221,7 +221,10 @@ def cleanup_query_results():
     Each time the job deletes only 100 query results so it won't choke the database in case of many such results.
     """
 
-    unused_query_results = models.QueryResult.unused().limit(100)
+    logging.info("Running query results clean up (removing maximum of %d unused results, that are %d days old or more)",
+                 settings.QUERY_RESULTS_CLEANUP_COUNT, settings.QUERY_RESULTS_CLEANUP_MAX_AGE)
+
+    unused_query_results = models.QueryResult.unused(settings.QUERY_RESULTS_CLEANUP_MAX_AGE).limit(settings.QUERY_RESULTS_CLEANUP_COUNT)
     total_unused_query_results = models.QueryResult.unused().count()
     deleted_count = models.QueryResult.delete().where(models.QueryResult.id << unused_query_results).execute()
 


Test patch:
Repository: getredash/redash

Issue:
Deleting and re-adding widgets to a dashboard breaks it
There's a specific set of steps that has messed up some of our users' dashboards:
1. Create a new dashboard
2. Add multiple widgets to it.
3. Remove all those widgets from the dashboard
4. Re-add some widgets
5. Click the "Edit Dashboard (Name/Layout)" button
6. Click Save without changing anything.
7. Refresh the page

This makes none of the widgets appear and causes the "Layout" array in the admin panel to contain one or more "null" values (depending on how many widgets you added/deleted):
![image](https://cloud.githubusercontent.com/assets/844493/11826038/76c749fa-a348-11e5-9f46-bbae43c4b6f6.png)

The only way to recover from this state is to manually delete the "null" values through the admin interface.

This is on re:dash version 0.8.2



Discussion:
**Thanks!** I've been trying to find the steps to reproduce this issue for such a long time.

Expect a fix in v0.9.0.


Resolving patch:
diff --git a/redash/handlers/widgets.py b/redash/handlers/widgets.py
--- a/redash/handlers/widgets.py
+++ b/redash/handlers/widgets.py
@@ -46,5 +46,7 @@ def delete(self, widget_id):
         widget = models.Widget.get(models.Widget.id == widget_id)
         widget.delete_instance()
 
+        return {'layout': widget.dashboard.layout }
+
 api.add_resource(WidgetListAPI, '/api/widgets', endpoint='widgets')
 api.add_resource(WidgetAPI, '/api/widgets/<int:widget_id>', endpoint='widget')


Test patch:
Repository: getredash/redash

Issue:
User should be redirected to his original destination after login with Google OAuth
If the user tried to open a page before being logged in, he should be redirected to this page after successful login.



Discussion:

Resolving patch:
diff --git a/redash/google_oauth.py b/redash/google_oauth.py
--- a/redash/google_oauth.py
+++ b/redash/google_oauth.py
@@ -1,8 +1,8 @@
 import logging
 from flask.ext.login import login_user
 import requests
-from flask import redirect, url_for, Blueprint, flash
-from flask_oauth import OAuth
+from flask import redirect, url_for, Blueprint, flash, request
+from flask_oauthlib.client import OAuth
 from redash import models, settings
 
 logger = logging.getLogger('google_oauth')
@@ -18,11 +18,9 @@
                           request_token_url=None,
                           request_token_params={
                               'scope': 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
-                              'response_type': 'code'
                           },
                           access_token_url='https://accounts.google.com/o/oauth2/token',
                           access_token_method='POST',
-                          access_token_params={'grant_type': 'authorization_code'},
                           consumer_key=settings.GOOGLE_CLIENT_ID,
                           consumer_secret=settings.GOOGLE_CLIENT_SECRET)
 
@@ -65,10 +63,10 @@ def create_and_login_user(name, email):
 
 @blueprint.route('/oauth/google', endpoint="authorize")
 def login():
-    # TODO, suport next
+    next = request.args.get('next','/')
     callback=url_for('.callback', _external=True)
     logger.debug("Callback url: %s", callback)
-    return google.authorize(callback=callback)
+    return google.authorize(callback=callback, state=next)
 
 
 @blueprint.route('/oauth/google_callback', endpoint="callback")
@@ -93,4 +91,6 @@ def authorized(resp):
 
     create_and_login_user(profile['name'], profile['email'])
 
-    return redirect(url_for('index'))
\ No newline at end of file
+    next = request.args.get('state','/')
+
+    return redirect(next)


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -3,6 +3,10 @@
 # Use different url for Celery to avoid DB being cleaned up:
 os.environ['REDASH_CELERY_BROKER'] = "redis://localhost:6379/6"
 
+# Dummy values for oauth login
+os.environ['REDASH_GOOGLE_CLIENT_ID'] = "dummy"
+os.environ['REDASH_GOOGLE_CLIENT_SECRET'] = "dummy"
+
 
 import logging
 from unittest import TestCase
Repository: getredash/redash

Issue:
Alert send Error(AttributeError: 'Organization' object has no attribute 'domain)
Hello.

Alert send Error.

```
01:51:24 worker.1 | [2016-01-07 01:51:24,764: ERROR/MainProcess] Task redash.tasks.check_alerts_for_query[6fd2a1aa-bb2b-4054-a6a1-2487c0bae30c] raised unexpected: AttributeError("'Organization' object has no attribute 'domain'",)
01:51:24 worker.1 | Traceback (most recent call last):
01:51:24 worker.1 |   File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 240, in trace_task
01:51:24 worker.1 |     R = retval = fun(*args, **kwargs)
01:51:24 worker.1 |   File "/opt/redash/current/redash/tasks.py", line 31, in __call__
01:51:24 worker.1 |     return super(BaseTask, self).__call__(*args, **kwargs)
01:51:24 worker.1 |   File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 437, in __protected_call__
01:51:24 worker.1 |     return self.run(*args, **kwargs)
01:51:24 worker.1 |   File "/opt/redash/current/redash/tasks.py", line 338, in check_alerts_for_query
01:51:24 worker.1 |     """.format(host=base_url(alert.query.org), alert_id=alert.id, query_id=query.id)
01:51:24 worker.1 |   File "/opt/redash/current/redash/tasks.py", line 309, in base_url
01:51:24 worker.1 |     if org.domain:
01:51:24 worker.1 | AttributeError: 'Organization' object has no attribute 'domain'
```



Discussion:

Resolving patch:
diff --git a/redash/tasks.py b/redash/tasks.py
--- a/redash/tasks.py
+++ b/redash/tasks.py
@@ -306,8 +306,9 @@ def version_check():
 
 
 def base_url(org):
-    if org.domain:
-        return 'https://{}'.format(org.domain)
+    if settings.MULTI_ORG:
+        return "https://{}/{}".format(settings.HOST, org.slug)
+
     return settings.HOST
 
 


Test patch:
Repository: getredash/redash

Issue:
AttributeError: 'datetime.timedelta' object has no attribute 'isoformat'
On the latest 0.9.2-rc:

```
[2016-01-21 14:30:36,838: ERROR/MainProcess] Task redash.tasks.execute_query[766d3f9f-68a6-4a64-8cd9-b7e4e18bf2af] raised unexpected: AttributeError("'datetime.timedelta' object has no attribute 'isoformat'",)
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/opt/redash/redash/tasks.py", line 31, in __call__
    return super(BaseTask, self).__call__(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 437, in __protected_call__
    return self.run(*args, **kwargs)
  File "/opt/redash/redash/tasks.py", line 286, in execute_query
    data, error = query_runner.run_query(annotated_query)
  File "/opt/redash/redash/query_runner/pg.py", line 132, in run_query
    json_data = json.dumps(data, cls=JSONEncoder)
  File "/usr/lib/python2.7/json/__init__.py", line 250, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/opt/redash/redash/utils.py", line 57, in default
    return o.isoformat()
AttributeError: 'datetime.timedelta' object has no attribute 'isoformat'
```



Discussion:

Resolving patch:
diff --git a/redash/utils.py b/redash/utils.py
--- a/redash/utils.py
+++ b/redash/utils.py
@@ -53,9 +53,12 @@ def default(self, o):
         if isinstance(o, decimal.Decimal):
             return float(o)
 
-        if isinstance(o, (datetime.date, datetime.time, datetime.timedelta)):
+        if isinstance(o, (datetime.date, datetime.time)):
             return o.isoformat()
-            
+
+        if isinstance(o, datetime.timedelta):
+            return str(o)
+
         super(JSONEncoder, self).default(o)
 
 


Test patch:
Repository: getredash/redash

Issue:
Download DataSheets as Excel file.
Csv file with utf-8 is hard to use in excel. So I want to download data sheets as .xlsx file



Discussion:
:+1: 


Resolving patch:
diff --git a/redash/handlers/query_results.py b/redash/handlers/query_results.py
--- a/redash/handlers/query_results.py
+++ b/redash/handlers/query_results.py
@@ -5,7 +5,7 @@
 
 from flask import make_response, request
 from flask.ext.restful import abort
-
+import xlsxwriter
 from redash import models, settings, utils
 from redash.wsgi import api
 from redash.tasks import QueryTask, record_event
@@ -105,6 +105,8 @@ def get(self, query_id=None, query_result_id=None, filetype='json'):
 
             if filetype == 'json':
                 response = self.make_json_response(query_result)
+            elif filetype == 'xlsx':
+                response = self.make_excel_response(query_result)
             else:
                 response = self.make_csv_response(query_result)
 
@@ -137,6 +139,28 @@ def make_csv_response(query_result):
         headers = {'Content-Type': "text/csv; charset=UTF-8"}
         return make_response(s.getvalue(), 200, headers)
 
+    @staticmethod
+    def make_excel_response(query_result):
+        s = cStringIO.StringIO()
+
+        query_data = json.loads(query_result.data)
+        book = xlsxwriter.Workbook(s)
+        sheet = book.add_worksheet("result")
+
+        column_names = []
+        for (c, col) in enumerate(query_data['columns']):
+            sheet.write(0, c, col['name'])
+            column_names.append(col['name'])
+
+        for (r, row) in enumerate(query_data['rows']):
+            for (c, name) in enumerate(column_names):
+                sheet.write(r+1, c, row[name])
+
+        book.close()
+
+        headers = {'Content-Type': "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}
+        return make_response(s.getvalue(), 200, headers)
+
 
 api.add_org_resource(QueryResultListAPI, '/api/query_results', endpoint='query_results')
 api.add_org_resource(QueryResultAPI,


Test patch:
diff --git a/tests/test_models.py b/tests/test_models.py
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -163,8 +163,9 @@ def test_interval_schedule_that_doesnt_need_reschedule(self):
     def test_exact_time_that_needs_reschedule(self):
         now = datetime.datetime.now()
         yesterday = now - datetime.timedelta(days=1)
-        schedule = "{:02d}:00".format(now.hour - 3)
-        self.assertTrue(models.should_schedule_next(yesterday, now, schedule))
+        scheduled_datetime = now - datetime.timedelta(hours=3)
+        scheduled_time = "{:02d}:00".format(scheduled_datetime.hour)
+        self.assertTrue(models.should_schedule_next(yesterday, now, scheduled_time))
 
     def test_exact_time_that_doesnt_need_reschedule(self):
         now = date_parse("2015-10-16 20:10")