Scout¶
Scout is a tool for City Purchasers to search for contract information, including line item information, and subscribe to receive updates when a contract is about to expire. It’s functionality revolves around the ever-present Search Form, which is backed by a Postgres Materialized View with full-text search. For more information about how this search is created, please see Full-text Search with Postgres and Sqlalchemy, parts one and two.
Scout also features Contract and Company detail pages, with pricing, detail, and metadata information for contracts and contact information for companies.
See also
How to use Scout, an internal product guide for more information about the user interface and user experience.
Models used¶
Forms¶
-
class
SearchForm
(*args, **kwargs)[source]¶ Form to handle Scout search and filter
Variables: - q – Search term – required
- company_name – Flag to include company name in search
- contract_description – Flag to include contract description in search
- line_item – Flag to include line item name in search
- financial_id – Flag to include financial ID in search
archived: Flag to include archived
ContractBase
objects in search - contract_type – Filter to include only
ContractBase
objects that match a certainContractType
Helpers¶
-
build_filter
(req_args, fields, search_for, filter_form, _all)[source]¶ Build the non-exclusive filter conditions for scout search
Along with building the filter for the search, build_filter also modifies the passed in
filter_form
, setting the checked property on the appropriate form fields.Parameters: - req_args – request.args from Flask.request
- fields –
list of three-tuples. Each three-tuple should contain the following:
- database column name
- desired output display name
- Model property that maps to the specific column name in question.
For build_filter, only the column name and Model property are used. For
build_cases()
, all are used. - search_for – string search term
- filter_form –
- _all – Boolean – true if we are searching across all fields, false otherwise
Returns: List of clauses that can be used in Sqlalchemy query filters
-
build_cases
(req_args, fields, search_for, _all)[source]¶ Build case statements for categorizing search matches in scout search
Parameters: - req_args – request.args from Flask.request
- fields –
list of three-tuples. Each three-tuple should contain the following:
- database column name
- desired output display name
- Model property that maps to the specific column name in question.
For build_cases, all three parts of the tuple are used
- search_for – string search term
- _all – Boolean – true if we are searching across all fields, false otherwise
Returns: List of clauses that can be used in a Sqlalchemy case expressions
-
feedback_handler
(contract, search_for=None)[source]¶ Allow user to send feedback on the data present in a specific contract
Parameters: - contract –
ContractBase
object - search_for – search term or None.
Returns: Redirects to or renders the appropriate feedback handling template
- contract –
-
add_archived_filter
(query, archived)[source]¶ Adds exclusionary filters and archived contracts to contract searches.
All searches exclude invalid contract objects, such as ones that have no financial id or no expiration date. Occasionally, the user will also want to search expired contracts. If the flag is passed, “archived” contracts, (which are either expired or manually flagged as no longer usuable) are shown as well.
Parameters: - query – Sqlalchemy contract search query
- archived – Boolean to determine if archived contracts should be included in search results
Returns: Original query with additional exclusionary filters and optionally archived contracts
-
find_contract_metadata
(search_for, case_statements, filter_or, filter_and, archived=False)[source]¶ Takes a search term, case statements, and filter clauses and returns out a list of search results objects to be rendered into the template.
Parameters: - search_for – User’s search term
- case_statements – An iterable of Sqlalchemy case expressions
- filter_or – An iterable of Sqlalchemy query filters, used for non-exclusionary filtering
- filter_and – An iterable of Sqlalchemy query filters, used for exclusionary filtering
- archived – Boolean of whether or not to add the
is_archived
filter
Returns: A Sqlalchemy resultset that contains the fields to render the search results view.
-
return_all_contracts
(filter_and, archived=False)[source]¶ Return all contracts in the event of an empty search
Parameters: - filter_and – An iterable of Sqlalchemy query filters, used for exclusionary filtering
- archived – Boolean of whether or not to add the
is_archived
filter
Returns: A Sqlalchemy resultset that contains the fields to render the search results view.
Views¶
-
GET
/scout/
¶ The landing page for scout. Renders the “big search” template.
Status Codes: - 200 OK – Renders the appropriate landing page.
-
POST
/scout/search
¶ The search results page for scout
In order to create permalinks to each search/filter result combination, POST methods have their form arguments popped off and then are immediately redirected to GET methods.
See also
purchasing.data.searches
for more on the search querySearchForm
for the search form constructionbuild_filter()
for how filters are builtbuild_cases()
for how case statements are built
Status Codes:
-
GET
/scout/search
¶ The search results page for scout
In order to create permalinks to each search/filter result combination, POST methods have their form arguments popped off and then are immediately redirected to GET methods.
See also
purchasing.data.searches
for more on the search querySearchForm
for the search form constructionbuild_filter()
for how filters are builtbuild_cases()
for how case statements are built
Status Codes:
-
POST
/scout/contracts/feedback/
(search_for)¶ Provide feedback about an empty search
This page is only viewable in the event of a search that returns 0 results.
Parameters: - search_for – Search term.
See also
feedback_handler()
for information on how the feedback is processed and handled
-
GET
/scout/contracts/feedback/
(search_for)¶ Provide feedback about an empty search
This page is only viewable in the event of a search that returns 0 results.
Parameters: - search_for – Search term.
See also
feedback_handler()
for information on how the feedback is processed and handled
-
GET
/scout/filter
¶ The landing page for filtering by departments
Status Codes: - 200 OK – Renders the appropriate landing page.
-
GET
/scout/filter/
(int: department_id)¶ Filter contracts by which ones have departmental subscribers
Parameters: - department_id – Department’s unique ID
Status Codes: - 200 OK – Renders template with all contracts followed by that department
- 404 Not Found – When department is not found with the specified ID
-
POST
/scout/contracts/
(int: contract_id)¶ Contract profile page
For GET requests, render the profile page. For POSTs, try to submit a new note.
Parameters: - contract_id – Unique ID for a
ContractBase
object
Status Codes: - 200 OK – Renders the contract profile template
- 302 Found – Try to post note, then redirect to the same page’s contract view
- 404 Not Found – Unique contract ID not found
- contract_id – Unique ID for a
-
GET
/scout/contracts/
(int: contract_id)¶ Contract profile page
For GET requests, render the profile page. For POSTs, try to submit a new note.
Parameters: - contract_id – Unique ID for a
ContractBase
object
Status Codes: - 200 OK – Renders the contract profile template
- 302 Found – Try to post note, then redirect to the same page’s contract view
- 404 Not Found – Unique contract ID not found
- contract_id – Unique ID for a
-
GET
/scout/companies/
(int: company_id)¶ Company profile page
Parameters: - contract_id – Unique ID for a
Company
object
Status Codes: - 200 OK – Renders the company profile template
- 404 Not Found – Unique company ID not found
- contract_id – Unique ID for a
-
POST
/scout/contracts/
(int: contract_id)/feedback
¶ Provide feedback about a contract
Parameters: - contract_id – Unique ID for a
ContractBase
object
See also
feedback_handler()
for information on how the feedback is processed and handled- contract_id – Unique ID for a
-
GET
/scout/contracts/
(int: contract_id)/feedback
¶ Provide feedback about a contract
Parameters: - contract_id – Unique ID for a
ContractBase
object
See also
feedback_handler()
for information on how the feedback is processed and handled- contract_id – Unique ID for a
-
GET
/scout/contracts/
(int: contract_id)/subscribe
¶ Subscribes a user to receive updates about a particular contract
Parameters: - contract_id – Unique ID for a
ContractBase
object
Status Codes: - 302 Found – Subscribe the current user and redirect to the page they came from
- 404 Not Found – Contract not found
- contract_id – Unique ID for a
-
GET
/scout/contracts/
(int: contract_id)/unsubscribe
¶ Unsubscribes a user from receiving updates about a particular contract
Parameters: - contract_id – Unique ID for a
ContractBase
object
Status Codes: - 302 Found – Unsubscribe the current user and redirect to the page they came from
- 404 Not Found – Contract not found
- contract_id – Unique ID for a
Nightly Jobs¶
-
class
CountyScrapeJob
(time_override=False)[source]¶ Nightly task to scrape the County for new line item information
See also
purchasing.data.importer.scrape_county.main()
purchasing.tasks.scrape_county_task()
-
start_time
¶ Override default start time, kick scrape task off immediately
-
class
ScoutJobBase
(time_override=False)[source]¶ Base class for Scout email notifications
See also
-
notification_props
¶ Placeholder for properties to be assigned to the Notification class.
Based on the implementation, this dictionary should include at least a ‘subjct’ and ‘html_template’ key.
Raises: NotImplementedError
-
-
class
ScoutContractsExpireTodayJob
(time_override=False)[source]¶ Get all contracts that expire today and send notification reminders
-
get_expiring_contracts
()[source]¶ Get all contracts expiring today
Returns: List of ContractBase
objects that expire today
-
-
class
ScoutContractsExpireSoonJob
(time_override=False)[source]¶ Get all contracts that are expiring in 30 days and send reminders
-
get_expiring_contracts
()[source]¶ Get all contracts expiring today
Returns: List of ContractBase
objects that expire in 30 days
-