Data retention lookup by type is only performed to get the number
of days, so we can update the service method to return the number
or the default directly.
Adds caching for service data retention. This removes separate API
client methods to retrieve individual data retention records by id
or type in favor of a single method that fetches and caches all
retention settings configured for the service. This makes it much
easier to invalidate cache when settings change.
Lookup by id or type is provided by helper methods in the service
model.
Since you can now see them when searching you should also be able to
select and move them. Which means that they needed to be included in
the `Form`’s list of possible choices of things to move.
The Jinja template for the ‘choose templates’ page is now pulling in
data from a lot of diparate places in order to work out what to show. As
we add more logic about what to show (in order to make the live search
work) it’s going to get harder to have all this logic in the Jinja
template.
This commit refactors it back into Python where we have more language
features for managing complex logic.
It’s a bit weird to call this file a model, in that it’s dealing with
some presentational logic, rather than just data. Conceptually it’s more
like a view model[1].
1. https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel
It was looking at the count of items at the root level (because it was
passing `parent_folder_id=None` as an argument).
This changes it to look at the total count of items for a service (which
was the intended behaviour).
We reckon it’s jarring to have the search box appear and disappear as
you navigate through the folders.
Instead it should appear whenever your service has more things
(templates or folders) than you can easily keep in your head (let’s go
with 7 for now).
This keeps the bahviour the same for current services that don’t have
any folders.
Currently if there’s nothing in a folder you just get an empty page.
This looks a bit broken, or like the page hasn’t finished loading.
This commit adds a message to the page to show that it’s intentionally
blank.
The message is contextual based on type of template, because there might
be templates in the current folder, even if you can’t see them at the
moment (because you’re filtering).
This makes the display of folders in the `<h1>` look like the prototype.
It alters the behaviour we’ve initially built here by only ever showing
a maximum of two levels of hierarchy (the current folders and its
parent).
Often people will be editing the existing name, not changing it
completely.
This matches what we do when someone wants to rename their template or
service.
A folder is relevant if it, or any of its descents contain a template of
the kind you’re looking for.
If you’re not filtering by template type then you should see all
folders.
Follows what we’re doing with the folders stuff. Avoids having too many
very straightforward methods on the model. Especially when the data they
need is only used by the form. So it’s better to encapsulate the logic
in the form.
Currently the order of API keys seems to be non-deterministic:
d46caa184e/app/dao/api_key_dao.py (L32-L39)
Generally we sort things alphabetically, unless there’s a good reason to
do otherwise.
This commit sorts the API keys alphabetically.
It’s redundant to make two API calls here, one to get all keys and one
to get a single key. Since the API calls are sequential we can speed
things up by getting the one key from the list of all keys.
This commit adds logic to:
- take the list of selected folders and templates
- split it into two lists (of folders and templates)
- `POST` that data to the API, to effect the movement of said folders
and templates
I’ve tried to architect it in such a way that we can easily add more
template ‘operations’ in the future, as we add more forms to the choose
template page.
This commit adds:
- checkboxes to let you select a template or folder
- radio buttons to let you select where to move those template(s) and/or
folder(s) to
It only does the `get` part of this work; handling the `post` and
calling API will be done in a subsequent commit.
This has two advantages:
- less logic in the view
- lets us filer the available navigation by which channels (email, text
letter) a service has available
We’re going to need a way to find out if, for a given ID:
1. its a template or a folder
2. if it belongs to a given service
To do 2., we can make a set of all the IDs, to see if a given ID is a
member of that set.
To do 1. we can make two sets, one for templates and one for folders.
The natural home for these sets is on the service model.
Clicking on template folder navigates to a page that displays that
folder's contents.
This reuses the existing choose template view by adding a filter
based on optional `template_folder_id` argument.
Service model methods are rewritten to match `all_templates` and
`get_template`. New `get_template_folder_path` method returns a
list of folders (from root to the current one) that the selected
folder is nested inside.
With the addition of template folders we need to filter templates
based on a combination of type and parent folder ID.
This replaces the existing `templates_by_type` method with
`get_templates`, which supports both type and parent folder filters,
avoiding a need to create specific methods for each use case.
We still need the templates property to exist in some way in order
to cache it, but it needs to be clear that it's different from
`.get_templates`. One option was to make it "private" (i.e. `_templates`),
and always use `.get_templates` in the rest of the code, but this requires
adding "include all folders" to `.get_templates`, which doesn't have an
obvious interface since `parent_folder_id=None` already means "top-level
only".
This will probably come up again when we need to look into adding
templates from nested folders into the page for live search, but
for now renaming `Service.templates` to `.all_templates` makes it
clear what the property contains.
The add new templates page now has option to add template folders.
Tweaked wording of other options and h1 to clarify options since it's
not all about templates any more.
Added api client and stuff for it
These helper functions for modifying a service permission were just
floating around loose in the view code.
A much better home for them is on the model. This will also make it
easy to reuse them in other views if we ever need to.
We have a lot of places in settings where we update something by passing
in the `service_id`. `current_service` already knows about `service_id`,
so it’s cleaner to encapsulate these updates inside the model.
During the migration from the model inhereting from a `dict` to being a
plain object it was useful to have these exceptions raised for quicker
debugging.
Now that all the code which relied on these methods has gone it’s OK
to remove them (attempts to call them will fall through to Python’s
native exception handling).
Making people use a property is a sure way to make sure they’re spelling
the name of the property correctly, and allows us to easily swap out
properties that call through to the underlying JSON, and properties
which are implemented as methods.
The API should always return something in the JSON for a property, even
if it’s just `None`.
There’s a lot of code in service settings which:
- talks to the API directly through the clients
- passes that information through to the Jinja template
By encapsulating this logic in the service model:
- the Jinja template can access the data directly
- the logic can be reused across multiple methods
The view here is rebuilding a pseudo-service object. Now that service
objects have templates it’s cleaner to use the actual service object.
Requires a small change to the `templates_by_type` method so that it can
filter by one or many template types (a user should be able to copy any
template whose type is enabled for their service, and the service
they’re copying from).
This commit is the first step to disentangling the models from the API
clients. With the models in the same folder as the API clients it makes
it hard to import the API clients within the model without getting a
circular import.
After this commit the user API clients still has this problem, but at
least the service API client doesn’t.