def index(page, service_code): if "filter" in request.args: service_code = request.args["filter"] url = "%s/requests.json" % app.config["OPEN311_SERVER"] recent_sr_timeframe = app.config.get("RECENT_SRS_TIME") # If SRS_PAGE_SIZE is set, use paging. Otherwise, fall back to a non-paged list from MAX_RECENT_SRS page_size = app.config.get("SRS_PAGE_SIZE") paged = page_size > 0 if not paged: page_size = app.config.get("MAX_RECENT_SRS", 50) page = 1 services_list = open311tools.services(app.config["OPEN311_SERVER"], app.config["OPEN311_API_KEY"]) service_name = "" for service in services_list: if service_code == service["service_code"]: service_name = service["service_name"] break if not service_name: service_code = "" params = {"extensions": "true", "page_size": page_size, "page": page, "service_code": service_code} if recent_sr_timeframe: start_datetime = datetime.datetime.utcnow() - datetime.timedelta(seconds=recent_sr_timeframe) params["start_date"] = start_datetime.isoformat() + "Z" if app.config["OPEN311_API_KEY"]: params["api_key"] = app.config["OPEN311_API_KEY"] r = requests.get(url, params=params) if r.status_code != 200: app.logger.error( "OPEN311: Failed to load recent requests from Open311 server. Status Code: %s, Response: %s", r.status_code, r.text, ) service_requests = None else: # need to slice with page_size in case an endpoint doesn't support page_size its API (it's non-standard) service_requests = r.json[:page_size] # we might receive SRs that were updated in the future (!); pretend like those updates were just now. # fixes https://github.com/codeforamerica/srtracker/issues/80 now = datetime.datetime.utcnow() for sr in service_requests: if "updated_datetime" in sr: # parse and ensure the date is naive for comparison to utcnow updated = iso8601.parse_date(sr["updated_datetime"]).astimezone(pytz.utc).replace(tzinfo=None) sr["updated_datetime"] = min(now, updated) return render_app_template( "index.html", service_requests=service_requests, page=page, services_list=services_list, service_code=service_code, service_name=service_name, )
def index(page, service_code): if 'filter' in request.args: service_code = request.args['filter'] url = '%s/requests.json' % app.config['OPEN311_SERVER'] recent_sr_timeframe = app.config.get('RECENT_SRS_TIME') # If SRS_PAGE_SIZE is set, use paging. Otherwise, fall back to a non-paged list from MAX_RECENT_SRS page_size = app.config.get('SRS_PAGE_SIZE') paged = page_size > 0 if not paged: page_size = app.config.get('MAX_RECENT_SRS', 50) page = 1 services_list = open311tools.services(app.config['OPEN311_SERVER'], app.config['OPEN311_API_KEY']) service_name = '' for service in services_list: if service_code == service['service_code']: service_name = service['service_name'] break if not service_name: service_code = '' params = { 'extensions': 'true', 'page_size': page_size, 'page': page, 'service_code': service_code } if recent_sr_timeframe: start_datetime = datetime.datetime.utcnow() - datetime.timedelta(seconds=recent_sr_timeframe) params['start_date'] = start_datetime.isoformat() + 'Z' if app.config['OPEN311_API_KEY']: params['api_key'] = app.config['OPEN311_API_KEY'] app.logger.debug('RECENT SRs: %s', params) r = requests.get(url, params=params) if r.status_code != 200: app.logger.error('OPEN311: Failed to load recent requests from Open311 server. Status Code: %s, Response: %s', r.status_code, r.text) service_requests = None else: # need to slice with page_size in case an endpoint doesn't support page_size its API (it's non-standard) service_requests = r.json[:page_size] return render_app_template('index.html', service_requests = service_requests, page = page, services_list = services_list, service_code = service_code, service_name = service_name)
def show_request(request_id): request_id = request_id.lstrip('#') # receive subscription form_errors = [] submitted_email = None if request.method == 'POST': submitted_email = request.form.get('update_email') if submitted_email: success = subscribe_to_sr(request_id, submitted_email) if not success: form_errors.append('Please use a valid e-mail address.') # TODO: Should probably use Three or something nice for this... url = '%s/requests/%s.json' % (app.config['OPEN311_SERVER'], request_id) params = {'extensions': 'true', 'legacy': 'false'} if app.config['OPEN311_API_KEY']: params['api_key'] = app.config['OPEN311_API_KEY'] r = requests.get(url, params=params) if r.status_code == 404: # TODO: how to generalize this? # Chicago's SR IDs are always \d\d-\d{8}, if we get just digits, reformat and try again request_id_digits = re.sub(r'\D', '', request_id) if len(request_id_digits) == 8: # Try prepending the year if it's only 8 digits request_id_digits = datetime.date.today().strftime( '%y') + request_id_digits if len(request_id_digits) == 10: reformatted = '%s-%s' % (request_id_digits[:2], request_id_digits[2:]) if reformatted != request_id: return redirect(url_for('show_request', request_id=reformatted)) # It would be nice to log this for analytical purposes (what requests are being checked that we can't show?) # but that would be better done through GA or KISS Metrics than through server logging services = open311tools.services(app.config['OPEN311_SERVER'], app.config['OPEN311_API_KEY']) return render_app_template('error_no_sr.html', request_id=request_id, services=services), 404 elif r.status_code != 200: app.logger.error('OPEN311: Error (not 404) loading data for SR %s', request_id) return render_app_template('error_311_api.html', request_id=request_id), 500 srs = r.json if srs: sr = fixup_sr(srs[0], request_id) if 'requested_datetime' in sr: sr['requested_datetime'] = iso8601.parse_date( sr['requested_datetime']) # sometimes an SR doesn't include notes even though there should always be an "opened" note if 'notes' not in sr: sr['notes'] = [] relevant_notes = 0 for note in sr['notes']: note['datetime'] = iso8601.parse_date(note['datetime']) if note['type'] in ('follow_on', 'follow_on_created', 'activity', 'closed'): relevant_notes += 1 # add follow-on closure data, fix types, etc, etc by_id = {} follow_on_open_count = 0 follow_on_close_count = 0 for note in sr['notes']: if note['type'] in ('follow_on', 'follow_on_created', 'follow_on_closed'): note_sr_id = note['extended_attributes']['service_request_id'] # old-style is just "follow_on" for everything related to follow-ons # new-style is "follow_on_created" and "follow_on_closed" # update old notes so templates don't get crazy complicated :( if note['type'] == 'follow_on_created' or note[ 'description'].endswith('Created'): note['type'] = 'follow_on_created' follow_on_open_count += 1 by_id[note_sr_id] = note elif note['type'] == 'follow_on_closed' or note[ 'description'].endswith('Closed'): follow_on_close_count += 1 note['type'] = 'follow_on_closed' if note_sr_id in by_id: original = by_id[note_sr_id] original['extended_attributes'][ 'closed_datetime'] = note['datetime'] # if we hit any follow_on_opened notes if follow_on_open_count > 0: # remove the notes that claim the request is closed sr['notes'] = [n for n in sr['notes'] if not n['type'] == 'closed'] # set the request to open sr['status'] = 'open' # if we hit as many follow_on_closed as follow_on_opened notes, then request is really closed if follow_on_open_count == follow_on_close_count: # set the request status to closed sr['status'] = 'closed' tmp_note = {} # add a closing note tmp_note['type'] = 'closed' tmp_note['summary'] = 'Request Completed' # this is brittle, but shouldn't break tmp_datetime = sorted([ n['extended_attributes']['closed_datetime'] for n in by_id.values() ]) # set the closed datetime to be the datetime of the last-closed follow-on tmp_note['datetime'] = tmp_datetime[0] # add the extra note sr['notes'].append(tmp_note) # if there's no activity yet, show 'under review' if relevant_notes == 0: sr['notes'].append({ 'type': 'activity', 'summary': 'Under review by %s staff' % sr.get('agency_responsible', '') }) subscribed = False if sr['status'] == 'open' and session.get('addr', None): # TODO: when subscription service supports more than e-mail, # we should probably be able to show all your subscriptions here subscribed = updater.subscription_exists(request_id, 'email', session.get('addr', '')) # test media # sr['media_url'] = sr['media_url'] or 'http://farm5.staticflickr.com/4068/4286605571_c1a1751fdc_n.jpg' body = render_app_template('service_request.html', sr=sr, subscribed=subscribed, errors=form_errors, submitted_email=submitted_email) return (body, 200, None) else: return render_app_template('error_no_sr.html', request_id=request_id), 404
def index(page, service_code): if 'filter' in request.args: service_code = request.args['filter'] url = '%s/requests.json' % app.config['OPEN311_SERVER'] recent_sr_timeframe = app.config.get('RECENT_SRS_TIME') # If SRS_PAGE_SIZE is set, use paging. Otherwise, fall back to a non-paged list from MAX_RECENT_SRS page_size = app.config.get('SRS_PAGE_SIZE') paged = page_size > 0 if not paged: page_size = app.config.get('MAX_RECENT_SRS', 50) page = 1 services_list = open311tools.services(app.config['OPEN311_SERVER'], app.config['OPEN311_API_KEY']) service_name = '' for service in services_list: if service_code == service['service_code']: service_name = service['service_name'] break if not service_name: service_code = '' params = { 'extensions': 'true', 'page_size': page_size, 'page': page, 'service_code': service_code } if recent_sr_timeframe: start_datetime = datetime.datetime.utcnow() - datetime.timedelta( seconds=recent_sr_timeframe) params['start_date'] = start_datetime.isoformat() + 'Z' if app.config['OPEN311_API_KEY']: params['api_key'] = app.config['OPEN311_API_KEY'] r = requests.get(url, params=params) if r.status_code != 200: app.logger.error( 'OPEN311: Failed to load recent requests from Open311 server. Status Code: %s, Response: %s', r.status_code, r.text) service_requests = None else: # need to slice with page_size in case an endpoint doesn't support page_size its API (it's non-standard) service_requests = r.json[:page_size] # we might receive SRs that were updated in the future (!); pretend like those updates were just now. # fixes https://github.com/codeforamerica/srtracker/issues/80 now = datetime.datetime.utcnow() for sr in service_requests: if 'updated_datetime' in sr: # parse and ensure the date is naive for comparison to utcnow updated = iso8601.parse_date(sr['updated_datetime']) \ .astimezone(pytz.utc).replace(tzinfo=None) sr['updated_datetime'] = min(now, updated) return render_app_template('index.html', service_requests=service_requests, page=page, services_list=services_list, service_code=service_code, service_name=service_name)
def show_request(request_id): request_id = request_id.lstrip('#') # receive subscription form_errors = [] submitted_email = None if request.method == 'POST': submitted_email = request.form.get('update_email') if submitted_email: success = subscribe_to_sr(request_id, submitted_email) if not success: form_errors.append('Please use a valid e-mail address.') # TODO: Should probably use Three or something nice for this... url = '%s/requests/%s.json' % (app.config['OPEN311_SERVER'], request_id) params = {'extensions': 'true', 'legacy': 'false'} if app.config['OPEN311_API_KEY']: params['api_key'] = app.config['OPEN311_API_KEY'] r = requests.get(url, params=params) if r.status_code == 404: # TODO: how to generalize this? # Chicago's SR IDs are always \d\d-\d{8}, if we get just digits, reformat and try again request_id_digits = re.sub(r'\D', '', request_id) if len(request_id_digits) == 8: # Try prepending the year if it's only 8 digits request_id_digits = datetime.date.today().strftime('%y') + request_id_digits if len(request_id_digits) == 10: reformatted = '%s-%s' % (request_id_digits[:2], request_id_digits[2:]) if reformatted != request_id: return redirect(url_for('show_request', request_id=reformatted)) # It would be nice to log this for analytical purposes (what requests are being checked that we can't show?) # but that would be better done through GA or KISS Metrics than through server logging services = open311tools.services(app.config['OPEN311_SERVER'], app.config['OPEN311_API_KEY']) return render_app_template('error_no_sr.html', request_id=request_id, services=services), 404 elif r.status_code != 200: app.logger.error('OPEN311: Error (not 404) loading data for SR %s', request_id) return render_app_template('error_311_api.html', request_id=request_id), 500 srs = r.json if srs: sr = fixup_sr(srs[0], request_id) if 'requested_datetime' in sr: sr['requested_datetime'] = iso8601.parse_date(sr['requested_datetime']) # sometimes an SR doesn't include notes even though there should always be an "opened" note if 'notes' not in sr: sr['notes'] = [] relevant_notes = 0 for note in sr['notes']: note['datetime'] = iso8601.parse_date(note['datetime']) if note['type'] in ('follow_on', 'follow_on_created', 'activity', 'closed'): relevant_notes += 1 # add follow-on closure data, fix types, etc, etc by_id = {} follow_on_open_count = 0 follow_on_close_count = 0 for note in sr['notes']: if note['type'] in ('follow_on', 'follow_on_created', 'follow_on_closed'): note_sr_id = note['extended_attributes']['service_request_id'] # old-style is just "follow_on" for everything related to follow-ons # new-style is "follow_on_created" and "follow_on_closed" # update old notes so templates don't get crazy complicated :( if note['type'] == 'follow_on_created' or note['description'].endswith('Created'): note['type'] = 'follow_on_created' follow_on_open_count += 1 by_id[note_sr_id] = note elif note['type'] == 'follow_on_closed' or note['description'].endswith('Closed'): follow_on_close_count += 1 note['type'] = 'follow_on_closed' if note_sr_id in by_id: original = by_id[note_sr_id] original['extended_attributes']['closed_datetime'] = note['datetime'] # if we hit any follow_on_opened notes if follow_on_open_count >0: # remove the notes that claim the request is closed sr['notes'] = [n for n in sr['notes'] if not n['type'] == 'closed'] # set the request to open sr['status'] = 'open' # if we hit as many follow_on_closed as follow_on_opened notes, then request is really closed if follow_on_open_count == follow_on_close_count: # set the request status to closed sr['status'] = 'closed' tmp_note = {} # add a closing note tmp_note['type'] = 'closed' tmp_note['summary'] = 'Request Completed' # this is brittle, but shouldn't break tmp_datetime = sorted([n['extended_attributes']['closed_datetime'] for n in by_id.values()]) # set the closed datetime to be the datetime of the last-closed follow-on tmp_note['datetime'] = tmp_datetime[0] # add the extra note sr['notes'].append(tmp_note) # if there's no activity yet, show 'under review' if relevant_notes == 0: sr['notes'].append({ 'type': 'activity', 'summary': 'Under review by %s staff' % sr.get('agency_responsible', '') }) subscribed = False if sr['status'] == 'open' and session.get('addr', None): # TODO: when subscription service supports more than e-mail, # we should probably be able to show all your subscriptions here subscribed = updater.subscription_exists(request_id, 'email', session.get('addr', '')) # test media # sr['media_url'] = sr['media_url'] or 'http://farm5.staticflickr.com/4068/4286605571_c1a1751fdc_n.jpg' body = render_app_template('service_request.html', sr=sr, subscribed=subscribed, errors=form_errors, submitted_email=submitted_email) return (body, 200, None) else: return render_app_template('error_no_sr.html', request_id=request_id), 404
def show_request(request_id): request_id = request_id.lstrip("#") # receive subscription form_errors = [] submitted_email = None if request.method == "POST": submitted_email = request.form.get("update_email") if submitted_email: success = subscribe_to_sr(request_id, submitted_email) if not success: form_errors.append("Please use a valid e-mail address.") # TODO: Should probably use Three or something nice for this... url = "%s/requests/%s.json" % (app.config["OPEN311_SERVER"], request_id) params = {"extensions": "true", "legacy": "false"} if app.config["OPEN311_API_KEY"]: params["api_key"] = app.config["OPEN311_API_KEY"] r = requests.get(url, params=params) if r.status_code == 404: # TODO: how to generalize this? # Chicago's SR IDs are always \d\d-\d{8}, if we get just digits, reformat and try again request_id_digits = re.sub(r"\D", "", request_id) if len(request_id_digits) == 8: # Try prepending the year if it's only 8 digits request_id_digits = datetime.date.today().strftime("%y") + request_id_digits if len(request_id_digits) == 10: reformatted = "%s-%s" % (request_id_digits[:2], request_id_digits[2:]) if reformatted != request_id: return redirect(url_for("show_request", request_id=reformatted)) # It would be nice to log this for analytical purposes (what requests are being checked that we can't show?) # but that would be better done through GA or KISS Metrics than through server logging services = open311tools.services(app.config["OPEN311_SERVER"], app.config["OPEN311_API_KEY"]) return render_app_template("error_no_sr.html", request_id=request_id, services=services), 404 elif r.status_code != 200: app.logger.error("OPEN311: Error (not 404) loading data for SR %s", request_id) return render_app_template("error_311_api.html", request_id=request_id), 500 srs = r.json if srs: sr = fixup_sr(srs[0], request_id) if "requested_datetime" in sr: sr["requested_datetime"] = iso8601.parse_date(sr["requested_datetime"]) # sometimes an SR doesn't include notes even though there should always be an "opened" note if "notes" not in sr: sr["notes"] = [] relevant_notes = 0 for note in sr["notes"]: note["datetime"] = iso8601.parse_date(note["datetime"]) if note["type"] in ("follow_on", "follow_on_created", "activity", "closed"): relevant_notes += 1 # add follow-on closure data, fix types, etc, etc by_id = {} follow_on_open_count = 0 follow_on_close_count = 0 for note in sr["notes"]: if note["type"] in ("follow_on", "follow_on_created", "follow_on_closed"): note_sr_id = note["extended_attributes"]["service_request_id"] # old-style is just "follow_on" for everything related to follow-ons # new-style is "follow_on_created" and "follow_on_closed" # update old notes so templates don't get crazy complicated :( if note["type"] == "follow_on_created" or note["description"].endswith("Created"): note["type"] = "follow_on_created" follow_on_open_count += 1 by_id[note_sr_id] = note elif note["type"] == "follow_on_closed" or note["description"].endswith("Closed"): follow_on_close_count += 1 note["type"] = "follow_on_closed" if note_sr_id in by_id: original = by_id[note_sr_id] original["extended_attributes"]["closed_datetime"] = note["datetime"] # if we hit any follow_on_opened notes if follow_on_open_count > 0: # remove the notes that claim the request is closed sr["notes"] = [n for n in sr["notes"] if not n["type"] == "closed"] # set the request to open sr["status"] = "open" # if we hit as many follow_on_closed as follow_on_opened notes, then request is really closed if follow_on_open_count == follow_on_close_count: # set the request status to closed sr["status"] = "closed" tmp_note = {} # add a closing note tmp_note["type"] = "closed" tmp_note["summary"] = "Request Completed" # this is brittle, but shouldn't break tmp_datetime = sorted([n["extended_attributes"]["closed_datetime"] for n in by_id.values()]) # set the closed datetime to be the datetime of the last-closed follow-on tmp_note["datetime"] = tmp_datetime[0] # add the extra note sr["notes"].append(tmp_note) # if there's no activity yet, show 'under review' if relevant_notes == 0: sr["notes"].append( {"type": "activity", "summary": "Under review by %s staff" % sr.get("agency_responsible", "")} ) subscribed = False if sr["status"] == "open" and session.get("addr", None): # TODO: when subscription service supports more than e-mail, # we should probably be able to show all your subscriptions here subscribed = updater.subscription_exists(request_id, "email", session.get("addr", "")) # test media # sr['media_url'] = sr['media_url'] or 'http://farm5.staticflickr.com/4068/4286605571_c1a1751fdc_n.jpg' body = render_app_template( "service_request.html", sr=sr, subscribed=subscribed, errors=form_errors, submitted_email=submitted_email ) return (body, 200, None) else: return render_app_template("error_no_sr.html", request_id=request_id), 404