DB: add brackets to _dict_query_where_clause

This method now includes brackets around the where clause which
it returns to avoid callers having to do so.
DB: _dict_query_where_clause logic now boolean

The "logic" parameter (AND / OR) has been changed to a "logic_or"
boolean parameter.  This is to prevent arbitrary strings being
inserted into the SQL query.
Web: consistent obs options template parameter

Use template parameter "selected_obsoptions" to match the
corresponding parameter "obsoptions".  Also simplified the
template code which produces the option choices.
Web: remove obsquerydict check for ''

Since the job_list handler in flask_app creates this dictionary
it can never be an empty string.
DB: validate table in _dict_query_where_clause

Now raises an exception if the table name doesn't look like a
valid SQL identifier.
DB: handle null case of _dict_query_where_clause
test: further test _dict_query_where_clause
DB: add Not class to _dict_query_where_clause

To represent non-matches, this commit introduces a "Not" wrapper
object.  If any of the single values or lists given to
_dict_query_where_clause are instances of the Not class then
the test for that column is inverted.
test: test DB find_jobs method with obsqueries

Test does not pass: it demonstrates the problem encountered
when trying to use join and count together in the find_jobs
method.  (This is the problem referred to in commit 3da5a78ade.)
DB: fix find_jobs count when used with obsqueries

The find_jobs method, as written, cannot use joins when the count option
is active.  With "GROUP BY" the database returns multiple count values
rather than the single total we are looking for, but without "GROUP BY"
it will count jobs multiple times if there are multiple matches in the
joined table.

This commit addresses the problem by replacing the join to the obs
table with a where clause matching the job identifier to a subquery of
job identifiers matching the obs query in the obs table.  The method
therefore no longer needs to be given a join string.
test: add more DB find_jobs obsqueries tests
DB: add NULL support to _dict_query_where_clause
DB: use _dict_query_where_clause in find_jobs

The find_jobs method now takes the obsquery as a dictionary which can be
passed to _dict_query_where_clause instead of a list of SQL strings.
This addresses the safety issue mentioned in commit f45db3dacf.
Web: omit null obsqueries from job_list page links

Only insert the observation query arguments which are set into
the dictionary used to build the URLs for the pagination links.
This is to prevent the URLs being longer than needed when
not all of the options are selected.
Web: improve display of pagination links

Set a constant color for links (link and visited pseudo-classes)
so that the links stay the same color as you navigate between
pages.  Included low-opacity placeholder text for currently
unavailable pagination links so that the links don't move
about on the page as their availability changes.