diff --git a/alembic/env.py b/alembic/env.py
index 230bc0d3..6c7b8a2b 100644
--- a/alembic/env.py
+++ b/alembic/env.py
@@ -14,7 +14,7 @@
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
-config.set_main_option("sqlalchemy.url", app.config['DATABASE_URL'])
+config.set_main_option("sqlalchemy.url", app.config['SQLALCHEMY_DATABASE_URI'])
# Interpret the config file for Python logging.
# This line sets up loggers basically.
diff --git a/alembic/versions/10855dae57b7_add_foreign_keys_bet.py b/alembic/versions/10855dae57b7_add_foreign_keys_bet.py
new file mode 100644
index 00000000..2e466140
--- /dev/null
+++ b/alembic/versions/10855dae57b7_add_foreign_keys_bet.py
@@ -0,0 +1,26 @@
+"""add foreign keys between User and Department
+
+Revision ID: 10855dae57b7
+Revises: 134e5fea7601
+Create Date: 2015-05-19 10:59:16.315012
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '10855dae57b7'
+down_revision = '134e5fea7601'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.alter_column('user', 'department', new_column_name='department_id')
+ op.add_column('department', sa.Column('primary_contact_id', sa.INTEGER, sa.ForeignKey("user.id")))
+ op.add_column('department', sa.Column('backup_contact_id', sa.INTEGER, sa.ForeignKey("user.id")))
+
+
+def downgrade():
+ op.drop_column('department', 'primary_contact_id')
+ op.drop_column('department', 'backup_contact_id')
+ op.alter_column('user', 'department_id', new_column_name='department')
diff --git a/alembic/versions/2de765e466ca_convert_created_date.py b/alembic/versions/2de765e466ca_convert_created_date.py
new file mode 100644
index 00000000..22c218dc
--- /dev/null
+++ b/alembic/versions/2de765e466ca_convert_created_date.py
@@ -0,0 +1,51 @@
+"""convert created datetimes to utc
+
+Revision ID: 2de765e466ca
+Revises: 10855dae57b7
+Create Date: 2015-05-19 23:01:13.266389
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '2de765e466ca'
+down_revision = '10855dae57b7'
+
+from alembic import op
+import sqlalchemy as sa
+from datetime import datetime
+from pytz import timezone, utc
+
+pacific = timezone('US/Pacific')
+Request = sa.Table(
+ 'request',
+ sa.MetaData(),
+ sa.Column('id', sa.Integer, primary_key=True),
+ sa.Column('date_created', sa.DateTime),
+)
+
+def upgrade():
+ connection = op.get_bind()
+
+ # Assume all existing requests were entered in Pacific time, and
+ # convert them to UTC.
+ for request in connection.execute(Request.select()):
+ date_created = request.date_created.replace(tzinfo=pacific)
+ date_created = date_created.astimezone(utc)
+ connection.execute(
+ Request.update().where(Request.c.id == request.id)
+ .values(date_created=date_created)
+ )
+
+
+def downgrade():
+ connection = op.get_bind()
+
+ # Assume all existing requests were entered in UTC, and convert
+ # them to Pacific time.
+ for request in connection.execute(Request.select()):
+ date_created = request.date_created.replace(tzinfo=utc)
+ date_created = date_created.astimezone(pacific)
+ connection.execute(
+ Request.update().where(Request.c.id == request.id)
+ .values(date_created=date_created)
+ )
diff --git a/public_records_portal/RequestPresenter.py b/public_records_portal/RequestPresenter.py
index 7a016aa8..5248e5bd 100644
--- a/public_records_portal/RequestPresenter.py
+++ b/public_records_portal/RequestPresenter.py
@@ -28,8 +28,8 @@ def __init__(self, request, qa = None, note = None, index = None, public = False
if self.staff:
if self.staff.email:
self.staff_email = self.staff.email
- if self.staff.department:
- self.staff_department = self.staff.department
+ if self.staff.department_id:
+ self.staff_department = self.staff.department_id
if self.staff.phone:
self.staff_phone = self.staff.phone
if self.staff.alias:
@@ -41,7 +41,7 @@ def __init__(self, request, qa = None, note = None, index = None, public = False
self.response = note
self.type = "note"
self.icon = "icon-edit icon-large"
-
+
def get_id(self):
return self.response.id
@@ -60,14 +60,14 @@ def display_text(self):
-
+
""" % (self.response.id, self.request.id)
else:
text = text + "
Requester hasn't answered yet.
"
return text
elif self.type == "note":
return "%s - Requester" %(self.response.text)
-
+
def get_icon(self):
return self.icon
diff --git a/public_records_portal/__init__.py b/public_records_portal/__init__.py
index 4eaddd55..5d82a5e7 100644
--- a/public_records_portal/__init__.py
+++ b/public_records_portal/__init__.py
@@ -11,7 +11,7 @@
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
-# Initialize Flask app
+# Initialize Flask app
app = Flask(__name__)
app.debug = True
@@ -24,9 +24,15 @@ def set_env(key, default = None):
elif default:
app.config[key] = default
+def set_bool_env(key, default = None):
+ if key in environ:
+ app.config[key] = environ[key].lower() in ('true', 'yes', 'on')
+ elif default is not None:
+ app.config[key] = default
+
# UPDATES TO THESE DEFAULTS SHOULD OCCUR IN YOUR .env FILE.
-set_env(key = 'APPLICATION_URL', default = "http://127.0.0.1:5000/")
+set_env(key = 'APPLICATION_URL', default = "http://127.0.0.1:5000/")
set_env(key = 'ENVIRONMENT', default="LOCAL")
# The default records liaison, to whom requests get routed to if no department is selected:
set_env(key = 'DEFAULT_OWNER_EMAIL', default = 'recordtrac@postcode.io')
@@ -40,7 +46,7 @@ def set_env(key, default = None):
# Currently due dates and overdue status is only showed to logged in agency staff
set_env(key = 'DAYS_TO_FULFILL', default = '10')
set_env(key = 'DAYS_AFTER_EXTENSION', default = '14')
-set_env(key = 'DAYS_UNTIL_OVERDUE', default = '2')
+set_env(key = 'DAYS_UNTIL_OVERDUE', default = '2')
set_env(key = 'TIMEZONE', default = "US/Pacific")
@@ -71,7 +77,7 @@ def set_env(key, default = None):
set_env(key = envvar)
# Database gets set slightly differently, to support difference between Flask and Heroku naming:
-app.config['SQLALCHEMY_DATABASE_URI'] = environ['DATABASE_URL']
+app.config['SQLALCHEMY_DATABASE_URI'] = environ['DATABASE_URL']
# Initialize database
db = SQLAlchemy(app)
diff --git a/public_records_portal/db_helpers.py b/public_records_portal/db_helpers.py
index 123a4904..e332ca90 100644
--- a/public_records_portal/db_helpers.py
+++ b/public_records_portal/db_helpers.py
@@ -1,4 +1,4 @@
-"""
+"""
.. module:: db_helpers
:synopsis: Functions that interact with the Postgres database via Flask-SQLAlchemy
.. modlueauthor:: Richa Agarwal
@@ -14,7 +14,7 @@
import uuid
import json
import os
-import logging
+import logging
### @export "get_subscriber"
@@ -264,9 +264,9 @@ def update_user(user, alias = None, phone = None, department = None, contact_for
if type(department) != int and not department.isdigit():
d = Department.query.filter_by(name = department).first()
if d:
- user.department = d.id
+ user.department_id = d.id
else:
- user.department = department
+ user.department_id = department
if contact_for:
if user.contact_for and contact_for not in user.contact_for:
contact_for = user.contact_for + "," + contact_for
@@ -328,7 +328,7 @@ def add_staff_participant(request_id, is_point_person = False, email = None, use
participant.is_point_person = True
participant.date_updated = datetime.now().isoformat()
if reason: # Update the reason
- participant.reason = reason
+ participant.reason = reason
app.logger.info("\n\nStaff participant with owner ID: %s is now the point of contact for request %s" %(participant.id, request_id))
else:
is_new = False
diff --git a/public_records_portal/filters.py b/public_records_portal/filters.py
index 51499b86..66999f24 100644
--- a/public_records_portal/filters.py
+++ b/public_records_portal/filters.py
@@ -20,6 +20,7 @@
app.jinja_env.filters['get_request_data_chronologically'] = prr.get_request_data_chronologically
app.jinja_env.filters['get_gravatar_url'] = gravatar.get_gravatar_url
app.jinja_env.filters['date'] = helpers.date
+app.jinja_env.filters['format_datetime'] = helpers.format_datetime
app.jinja_env.filters['explain_action'] = helpers.explain_action
app.jinja_env.filters['tutorial'] = helpers.tutorial
app.jinja_env.filters['new_lines'] = helpers.new_lines
diff --git a/public_records_portal/helpers.py b/public_records_portal/helpers.py
index 8fbf15fe..d5642341 100644
--- a/public_records_portal/helpers.py
+++ b/public_records_portal/helpers.py
@@ -56,6 +56,16 @@ def date(obj):
except: # Not a datetime object
return notifications.format_date(datetime.strptime(obj, "%Y-%m-%dT%H:%M:%S.%f"))
+def format_datetime(obj, format):
+ """ Take a datetime or datetime-like object and return a formatted datetime string. """
+ if not obj:
+ return None
+ try:
+ return localize(obj).strftime(format)
+ except: # Not a datetime object
+ date_obj = datetime.strptime(obj, "%Y-%m-%dT%H:%M:%S.%f")
+ return localize(date_obj).strftime(format)
+
def timestamp(obj):
return localize(obj).strftime('%H:%M:%S')
diff --git a/public_records_portal/models.py b/public_records_portal/models.py
index 3bca0deb..e24c170d 100644
--- a/public_records_portal/models.py
+++ b/public_records_portal/models.py
@@ -15,6 +15,7 @@
from sqlalchemy import and_, or_
from datetime import datetime, timedelta
+from pytz import utc
from public_records_portal import db, app
from werkzeug.security import generate_password_hash, check_password_hash
import json
@@ -31,14 +32,17 @@ class User(db.Model):
phone = db.Column(db.String())
date_created = db.Column(db.DateTime)
password = db.Column(db.String(255))
- department = db.Column(Integer, ForeignKey("department.id"))
- current_department = relationship("Department", foreign_keys = [department], uselist = False)
+ department_id = db.Column(Integer, ForeignKey("department.id", use_alter=True, name="fk_department"))
contact_for = db.Column(db.String()) # comma separated list
backup_for = db.Column(db.String()) # comma separated list
owners = relationship("Owner")
subscribers = relationship("Subscriber")
is_staff = db.Column(db.Boolean, default = False) # Is this user an active agency member?
+ current_department = relationship("Department",
+ foreign_keys=[department_id],
+ lazy='joined', uselist=False)
+
def is_authenticated(self):
return True
def is_active(self):
@@ -63,7 +67,7 @@ def __init__(self, email=None, alias = None, phone=None, department = None, cont
self.phone = phone
self.date_created = datetime.now().isoformat()
if department and department != "":
- self.department = department
+ self.department_id = department
if contact_for and contact_for != "":
self.contact_for = contact_for
if backup_for and backup_for != "":
@@ -88,9 +92,21 @@ class Department(db.Model):
date_created = db.Column(db.DateTime)
date_updated = db.Column(db.DateTime)
name = db.Column(db.String(), unique=True)
- users = relationship("User") # The list of users in this department
+ users = relationship("User", foreign_keys=[User.department_id], post_update=True) # The list of users in this department
requests = relationship("Request", order_by = "Request.date_created.asc()") # The list of requests currently associated with this department
- def __init__(self, name):
+
+ primary_contact_id = db.Column(Integer, ForeignKey("user.id"))
+ backup_contact_id = db.Column(Integer, ForeignKey("user.id"))
+ primary_contact = relationship(User,
+ foreign_keys=[primary_contact_id],
+ primaryjoin=(primary_contact_id == User.id),
+ uselist=False, post_update=True)
+ backup_contact = relationship(User,
+ foreign_keys=[backup_contact_id],
+ primaryjoin=(backup_contact_id == User.id),
+ uselist=False, post_update=True)
+
+ def __init__(self, name=''):
self.name = name
self.date_created = datetime.now().isoformat()
def __repr__(self):
@@ -101,7 +117,7 @@ def get_name(self):
return self.name or "N/A"
### @export "Request"
-class Request(db.Model):
+class Request(db.Model):
# The public records request
__tablename__ = 'request'
id = db.Column(db.Integer, primary_key =True)
@@ -124,7 +140,7 @@ class Request(db.Model):
def __init__(self, text, creator_id = None, offline_submission_type = None, date_received = None):
self.text = text
- self.date_created = datetime.now().isoformat()
+ self.date_created = datetime.now(utc).isoformat()
self.creator_id = creator_id
self.offline_submission_type = offline_submission_type
if date_received and type(date_received) is datetime:
@@ -142,7 +158,7 @@ def set_due_date(self):
self.due_date = self.date_received + timedelta(days = int(app.config['DAYS_TO_FULFILL']))
def extension(self):
- self.extended = True
+ self.extended = True
self.due_date = self.due_date + timedelta(days = int(app.config['DAYS_AFTER_EXTENSION']))
def point_person(self):
for o in self.owners:
@@ -154,7 +170,7 @@ def all_owners(self):
for o in self.owners:
all_owners.append(o.user.get_alias())
return all_owners
-
+
def requester(self):
if self.subscribers:
return self.subscribers[0] or None # The first subscriber is always the requester
@@ -207,11 +223,11 @@ def open(self):
def due_soon(self):
two_days = datetime.now() + timedelta(days = 2)
return and_(self.due_date < two_days, self.due_date > datetime.now(), ~self.closed)
-
+
@hybrid_property
def overdue(self):
return and_(self.due_date < datetime.now(), ~self.closed)
-
+
@hybrid_property
def closed(self):
return Request.status.ilike("%closed%")
@@ -236,12 +252,12 @@ def __repr__(self):
return "" %(self.question, self.answer)
### @export "Owner"
-class Owner(db.Model):
+class Owner(db.Model):
# A member of city staff assigned to a particular request, that may or may not upload records towards that request.
__tablename__ = 'owner'
id = db.Column(db.Integer, primary_key =True)
user_id = Column(Integer, ForeignKey('user.id'))
- user = relationship("User", uselist = False)
+ user = relationship("User", uselist = False, lazy='joined')
request_id = db.Column(db.Integer, db.ForeignKey('request.id'))
request = relationship("Request", foreign_keys = [request_id])
active = db.Column(db.Boolean, default = True) # Indicate whether they're still involved in the request or not.
@@ -259,15 +275,17 @@ def __init__(self, request_id, user_id, reason= None, is_point_person = False):
self.is_point_person = is_point_person
def __repr__(self):
return '' %self.id
+ def __str__(self):
+ return str(self.user)
### @export "Subscriber"
-class Subscriber(db.Model):
+class Subscriber(db.Model):
# A person subscribed to a request, who may or may not have created the request, and may or may not own a part of the request.
__tablename__ = 'subscriber'
id = db.Column(db.Integer, primary_key = True)
should_notify = db.Column(db.Boolean, default = True) # Allows a subscriber to unsubscribe
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
- user = relationship("User", uselist = False)
+ user = relationship("User", uselist = False, lazy='joined')
request_id = db.Column(db.Integer, db.ForeignKey('request.id'))
date_created = db.Column(db.DateTime)
owner_id = db.Column(db.Integer, db.ForeignKey('owner.id')) # Not null if responsible for fulfilling a part of the request. UPDATE 6-11-2014: This isn't used. we should get rid of it.
@@ -277,6 +295,8 @@ def __init__(self, request_id, user_id, creator = False):
self.date_created = datetime.now().isoformat()
def __repr__(self):
return '' %self.user_id
+ def __str__(self):
+ return str(self.user)
### @export "Record"
class Record(db.Model):
@@ -287,7 +307,7 @@ class Record(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # The user who uploaded the record, right now only city staff can
doc_id = db.Column(db.Integer) # The document ID. Currently using Scribd API to upload documents.
request_id = db.Column(db.Integer, db.ForeignKey('request.id')) # The request this record was uploaded for
- description = db.Column(db.String(400)) # A short description of what the record is.
+ description = db.Column(db.String(400)) # A short description of what the record is.
filename = db.Column(db.String(400)) # The original name of the file being uploaded.
url = db.Column(db.String()) # Where it exists on the internet.
download_url = db.Column(db.String()) # Where it can be downloaded on the internet.
@@ -332,6 +352,6 @@ class Visualization(db.Model):
def __init__(self, type_viz, content):
self.type_viz = type_viz
self.content = content
- self.date_created = datetime.now().isoformat()
+ self.date_created = datetime.now(utc).isoformat()
def __repr__(self):
return '' % self.type_viz
diff --git a/public_records_portal/prflask.py b/public_records_portal/prflask.py
index c942c025..046f5f75 100644
--- a/public_records_portal/prflask.py
+++ b/public_records_portal/prflask.py
@@ -8,11 +8,14 @@
+from datetime import date
from public_records_portal import app, models, db, views
from views import * # Import all the functions that render templates
from flask.ext.restless import APIManager
from flask.ext.admin import Admin, expose, BaseView, AdminIndexView
-from flask.ext.admin.contrib.sqlamodel import ModelView
+from flask.ext.admin.contrib.sqla import ModelView
+from jinja2.filters import do_mark_safe
+from wtforms.validators import ValidationError
# Create API
@@ -33,52 +36,81 @@ class HomeView(AdminIndexView):
def home(self):
return self.render('admin.html')
def is_accessible(self):
- if current_user.is_authenticated():
- if 'LIST_OF_ADMINS' in app.config:
- admins = app.config['LIST_OF_ADMINS'].split(",")
- if current_user.email.lower() in admins:
- return True
- return False
+ if current_user.is_authenticated():
+ if 'LIST_OF_ADMINS' in app.config:
+ admins = app.config['LIST_OF_ADMINS'].split(",")
+ if current_user.email.lower() in admins:
+ return True
+ return False
# Create Admin
admin = Admin(app, name='RecordTrac Admin', url='/admin', index_view = HomeView(name='Home'))
class AdminView(ModelView):
def is_accessible(self):
- if current_user.is_authenticated():
- if 'LIST_OF_ADMINS' in app.config:
- admins = app.config['LIST_OF_ADMINS'].split(",")
- if current_user.email.lower() in admins:
- return True
+ if current_user.is_authenticated():
+ if 'LIST_OF_ADMINS' in app.config:
+ admins = app.config['LIST_OF_ADMINS'].split(",")
+ if current_user.email.lower() in admins:
+ return True
return False
+def postdate_check(form, field):
+ if field.data.date() > date.today():
+ raise ValidationError('This field cannot be post-dated')
+
class RequestView(AdminView):
- can_create = False
- can_edit = True
- column_list = ('id', 'text', 'date_created', 'status') # The fields the admin can view
- column_searchable_list = ('status', 'text') # The fields the admin can search a request by
- form_excluded_columns = ('date_created', 'extended', 'status', 'status_updated', 'current_owner') # The fields the admin cannot edit.
+ can_create = False
+ can_edit = True
+ column_list = ('id', 'text', 'date_created', 'status') # The fields the admin can view
+ column_labels = dict(date_created='Date Created (UTC)')
+ column_searchable_list = ('status', 'text') # The fields the admin can search a request by
+ form_excluded_columns = ('date_created', 'extended', 'status', 'status_updated', 'current_owner') # The fields the admin cannot edit.
+ form_args = dict(date_received={
+ 'validators': [postdate_check]
+ })
class RecordView(AdminView):
- can_create = False
- column_searchable_list = ('description', 'filename', 'url', 'download_url', 'access')
- column_list = ('request_id', 'description', 'filename', 'url', 'download_url', 'access')
- can_edit = False
+ can_create = False
+ column_searchable_list = ('description', 'filename', 'url', 'download_url', 'access')
+ column_list = ('request_id', 'description', 'filename', 'url', 'download_url', 'access')
+ can_edit = False
class QAView(AdminView):
- can_create = False
- can_edit = True
- column_list = ('request_id', 'question', 'answer', 'date_created')
- form_excluded_columns = ('date_created')
+ can_create = False
+ can_edit = True
+ column_list = ('request_id', 'question', 'answer', 'date_created')
+ form_excluded_columns = ('date_created')
class NoteView(AdminView):
- can_create = False
- can_edit = True
- column_list = ('request_id', 'text', 'date_created')
- form_excluded_columns = ('date_created')
-
+ can_create = False
+ can_edit = True
+ column_list = ('request_id', 'text', 'date_created')
+ form_excluded_columns = ('date_created')
+
+class UserView(AdminView):
+ can_create = True
+ can_edit = True
+ column_list = ('alias', 'email', 'current_department', 'phone', 'is_staff')
+ column_labels = dict(alias='Name', current_department='Department', phone='Phone #')
+ column_descriptions = dict(is_staff='Determines whether the user can log in and edit data through this interface.')
+ form_excluded_columns = ('date_created', 'password', 'contact_for', 'backup_for')
+
+class DepartmentView(AdminView):
+ can_create = True
+ can_edit = True
+ column_list = ('name', 'primary_contact', 'backup_contact')
+ column_descriptions = dict(backup_contact='Note that if you want to assign a user that does not yet exist as the primary or backup contact for this department, you must create the user first.')
+
+ form_columns = column_list
+ form_excluded_columns = ('date_created', 'date_updated')
+ form_args = dict(backup_contact={
+ 'description': do_mark_safe(column_descriptions['backup_contact'])
+ })
admin.add_view(RequestView(models.Request, db.session))
admin.add_view(RecordView(models.Record, db.session))
admin.add_view(NoteView(models.Note, db.session))
admin.add_view(QAView(models.QA, db.session))
+admin.add_view(UserView(models.User, db.session))
+admin.add_view(DepartmentView(models.Department, db.session))
diff --git a/public_records_portal/prr.py b/public_records_portal/prr.py
index 40b3d33f..d5c3d80f 100644
--- a/public_records_portal/prr.py
+++ b/public_records_portal/prr.py
@@ -26,6 +26,8 @@
def add_resource(resource, request_body, current_user_id = None):
fields = request_body
if "extension" in resource:
+ if not fields.getlist('extend_reason') and not fields.getlist('extend_reasons'):
+ return "You must select a reason for the extension."
return request_extension(int(fields['request_id']), fields.getlist('extend_reason'), current_user_id)
if "note" in resource:
return add_note(request_id = int(fields['request_id']), text = fields['note_text'], user_id = current_user_id, passed_spam_filter = True) # Bypass spam filter because they are logged in.
@@ -148,10 +150,10 @@ def add_link(request_id, url, description, user_id):
return record_id
return False
-### @export "make_request"
+### @export "make_request"
def make_request(text, email = None, user_id = None, phone = None, alias = None, department = None, passed_spam_filter = False, offline_submission_type = None, date_received = None):
""" Make the request. At minimum you need to communicate which record(s) you want, probably with some text."""
- if not passed_spam_filter:
+ if not passed_spam_filter:
return None, False
request_id = find_request(text)
if request_id: # Same request already exists
@@ -177,7 +179,7 @@ def make_request(text, email = None, user_id = None, phone = None, alias = None,
generate_prr_emails(request_id, notification_type = "Request made", user_id = subscriber_user_id) # Send them an e-mail notification
return request_id, True
-### @export "add_subscriber"
+### @export "add_subscriber"
def add_subscriber(request_id, email):
user_id = create_or_return_user(email = email)
subscriber_id, is_new_subscriber = create_subscriber(request_id = request_id, user_id = user_id)
@@ -186,7 +188,7 @@ def add_subscriber(request_id, email):
return subscriber_id
return False
-### @export "ask_a_question"
+### @export "ask_a_question"
def ask_a_question(request_id, user_id, question):
""" City staff can ask a question about a request they are confused about."""
req = get_obj("Request", request_id)
@@ -211,12 +213,12 @@ def answer_a_question(qa_id, answer, subscriber_id = None, passed_spam_filter =
generate_prr_emails(request_id = request_id, notification_type = "Question answered")
return True
-### @export "open_request"
+### @export "open_request"
def open_request(request_id):
change_request_status(request_id, "Open")
-### @export "assign_owner"
-def assign_owner(request_id, reason, email = None):
+### @export "assign_owner"
+def assign_owner(request_id, reason, email = None):
""" Called any time a new owner is assigned. This will overwrite the current owner."""
req = get_obj("Request", request_id)
past_owner_id = None
@@ -230,9 +232,9 @@ def assign_owner(request_id, reason, email = None):
return owner_id
app.logger.info("\n\nA new owner has been assigned: Owner: %s" % owner_id)
- new_owner = get_obj("Owner", owner_id)
+ new_owner = get_obj("Owner", owner_id)
# Update the associated department on request
- update_obj(attribute = "department_id", val = new_owner.user.department, obj = req)
+ update_obj(attribute = "department_id", val = new_owner.user.department_id, obj = req)
user_id = get_attribute(attribute = "user_id", obj_id = owner_id, obj_type = "Owner")
# Send notifications
if is_new_owner:
@@ -278,7 +280,7 @@ def get_responses_chronologically(req):
def set_directory_fields():
# Set basic user data
if 'STAFF_URL' in app.config:
- # This gets run at regular internals via db_users.py in order to keep the staff user list up to date. Before users are added/updated, ALL users get reset to 'inactive', and then only the ones in the current CSV are set to active.
+ # This gets run at regular internals via db_users.py in order to keep the staff user list up to date. Before users are added/updated, ALL users get reset to 'inactive', and then only the ones in the current CSV are set to active.
for user in User.query.filter(User.is_staff == True).all():
update_user(user = user, is_staff = False)
csvfile = urllib.urlopen(app.config['STAFF_URL'])
@@ -296,7 +298,7 @@ def set_directory_fields():
else:
app.logger.info("\n\n Please update the config variable LIAISONS_URL for where to find department liaison data for your agency.")
else:
- app.logger.info("\n\n Please update the config variable STAFF_URL for where to find csv data on the users in your agency.")
+ app.logger.info("\n\n Please update the config variable STAFF_URL for where to find csv data on the users in your agency.")
if 'DEFAULT_OWNER_EMAIL' in app.config and 'DEFAULT_OWNER_REASON' in app.config:
create_or_return_user(email = app.config['DEFAULT_OWNER_EMAIL'].lower(), alias = app.config['DEFAULT_OWNER_EMAIL'], department = app.config['DEFAULT_OWNER_REASON'], is_staff = True)
app.logger.info("\n\n Creating a single user from DEFAULT_OWNER_EMAIL and DEFAULT_OWNER_REASON for now. You may log in with %s" %(app.config['DEFAULT_OWNER_EMAIL']))
diff --git a/public_records_portal/static/js/manage_request_city.js b/public_records_portal/static/js/manage_request_city.js
index 3bb56d93..dcdac747 100644
--- a/public_records_portal/static/js/manage_request_city.js
+++ b/public_records_portal/static/js/manage_request_city.js
@@ -137,7 +137,7 @@ function prepareStaffTypeahead(){
$.each(user_data, function (i, staff) {
emails.push(staff['email']);
map[staff['alias'] + " - " + staff['email']] = staff['email'];
- contacts.push(staff['alias'] + " - " + staff['email']);
+ contacts.push(staff['alias'] + " - " + staff['email']);
});
});
return { map:map, emails:emails, contacts:contacts }
diff --git a/public_records_portal/static/js/new_request.js b/public_records_portal/static/js/new_request.js
index 24c70d25..2a3109d5 100644
--- a/public_records_portal/static/js/new_request.js
+++ b/public_records_portal/static/js/new_request.js
@@ -1,20 +1,34 @@
$(document).ready(function(){
+ $.validator.addMethod('nopostdate', function(value, element) {
+ var eod = new Date();
+ var dateval = new Date(value);
+
+ eod.setHours(23, 59, 59, 999);
+ return this.optional(element) || dateval <= eod;
+ }, "This field must not be postdated.");
+
/* validates add a request form */
$("#submitRequest").validate({
rules: {
request_text: {
required: true,
minlength: 2
- }
- },
+ },
+ date_received: {
+ nopostdate: true
+ }
+ },
+ messages: {
+ date_received: "You must select a date in the past."
+ },
highlight: function(element) {
$(element).closest('.control-group').removeClass('success').addClass('error');
- },
+ },
success: function(element) {
element
- .closest('.control-group').removeClass('error').addClass('success');
- }
+ .closest('.control-group').removeClass('error').addClass('success');
+ }
});
diff --git a/public_records_portal/templates/_response_widget.html b/public_records_portal/templates/_response_widget.html
index 09cded08..f7e039c9 100644
--- a/public_records_portal/templates/_response_widget.html
+++ b/public_records_portal/templates/_response_widget.html
@@ -155,7 +155,7 @@ Reason for extension
-
+