dvModelPageResolver function
DVPageDataResolver
dvModelPageResolver(
- List<
DVModelPageSpec> specs, - DVPageQuery query, {
- String? applicationFavicon,
A resolver over specs: the request's pattern names the model, the
parameter names the row, query reads it. A row that is not there is a
hidden page; a pattern no spec owns is nobody's, null.
The model's view policy is asked as nobody, whoever sent the request. What this resolves is the head, the structured data and the crawler text, and it is kept per path and handed to every reader after this one -- so resolving it as a signed-in reader would serve their view of the record to everybody. A reader the policy admits sees the record on the page the client renders; the server's document describes what anybody may see.
Implementation
DVPageDataResolver dvModelPageResolver(
List<DVModelPageSpec> specs,
DVPageQuery query, {
String? applicationFavicon,
}) {
final ownedSpecs = List<DVModelPageSpec>.unmodifiable(specs);
final DVPageDataResolver resolver = (DVPageRequest request) async {
for (final DVModelPageSpec spec in ownedSpecs) {
if (spec.route != request.pattern) continue;
final String? key = request.params[spec.param];
if (key == null) return null;
// Not even read: nothing of a person's row is ever page data.
if (spec.personal) return dvModelPageNotFound(spec);
// Resolved here rather than stored in the spec. Under
// schemaPerTenant the table name depends on which tenant is asking,
// and the spec list is built once for the process -- so a resolved
// name in it would be the first tenant's answer served to everybody.
final List<Map<String, Object?>> rows = await query(
'SELECT * FROM ${dvTenantTable(spec.table)} '
'WHERE ${spec.keyField} = ?',
<Object?>[key],
);
if (rows.isEmpty) return dvModelPageNotFound(spec);
final Map<String, Object?> row = rows.first;
if (!await const DVModelPageAccess().mayView(
spec.model,
null,
row,
personal: spec.personal,
declaredViewPolicy: spec.viewPolicy,
)) {
return dvModelPageNotFound(spec);
}
return dvModelPageData(
spec,
row,
applicationFavicon: applicationFavicon,
);
}
return null;
};
_modelResolverPatterns[resolver] = {for (final spec in ownedSpecs) spec.route};
return resolver;
}