Coverage for control/details.py : 92%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Detail records of master records of tables.
3* Rendering
4* Customization
5"""
7from config import Config as C, Names as N
8from control.utils import pick as G, E
9from control.html import HtmlElements as H
10from control.perm import checkTable
12CT = C.tables
14DETAILS = CT.details
17class Details:
18 """Deals with detail records."""
20 inheritProps = (
21 N.context,
22 N.uid,
23 N.eppn,
24 N.tableObj,
25 N.mkTable,
26 N.table,
27 N.record,
28 N.eid,
29 N.fields,
30 N.prov,
31 N.perm,
32 N.wfitem,
33 N.kind,
34 )
36 def __init__(self, recordObj):
37 """## Initialization
39 Store the incoming information.
41 A number of properties will be inherited from the master record object
42 that spawns a detail record object.
44 Parameters
45 ----------
46 recordObj: object
47 A `control.record.Record` object (or one of a derived class)
48 """
50 for prop in Details.inheritProps:
51 setattr(self, prop, getattr(recordObj, prop, None))
53 self.details = {}
54 """*dict* Stores the details of this record.
56 Keyed by the name of the detail table, values are lists of detail
57 records in that detail table.
58 """
60 def tablePerm(self, table):
61 context = self.context
62 auth = context.auth
64 return checkTable(auth, table)
66 def fetchDetails(self, dtable, sortKey=None):
67 """Fetch detail records from the database.
69 !!! caution
70 The details will only be fetched if the user has permissions
71 to list the detail table!
73 !!! caution "Workflow restrictions"
74 There might be additional restrictions on individual records
75 due to workflow. Some records may not be readable.
76 They will be filtered out.
78 Parameters
79 ----------
80 dtable: string
81 The name of the table in which the detail records are stored.
82 sortKey: function
83 A function to sort the detail records.
85 Returns
86 -------
87 void
88 The detail records are stored in the `details` attribute, which is a
89 dict keyed by the names of the detail tables.
90 """
92 if not self.tablePerm(dtable): 92 ↛ 93line 92 didn't jump to line 93, because the condition on line 92 was never true
93 return
95 context = self.context
96 db = context.db
97 mkTable = self.mkTable
98 table = self.table
99 eid = self.eid
101 dtableObj = mkTable(context, dtable)
102 drecords = db.getDetails(dtable, table, eid, sortKey=sortKey)
103 self.details[dtable] = (
104 dtableObj,
105 tuple(drecord for drecord in drecords if dtableObj.readable(drecord)),
106 )
108 def wrap(self, readonly=False, showTable=None, showEid=None):
109 """Wrap the details of all tables for this record into HTML.
111 Parameters
112 ----------
113 readonly: boolean, optional `False`
114 Whether the records should be presented in readonly form.
115 showTable: string
116 Name of the detail table of which record `showEid` should be opened.
117 showEid: ObjectId
118 Id of the detail record that should be initially opened.
120 Returns
121 -------
122 string(html)
123 """
125 table = self.table
127 for detailTable in G(DETAILS, table, default=[]):
128 self.fetchDetails(detailTable)
130 details = self.details
132 return H.join(
133 self.wrapDetail(
134 detailTable,
135 readonly=readonly,
136 showEid=showEid if detailTable == showTable else None,
137 )
138 for detailTable in details
139 )
141 def wrapDetail(
142 self,
143 dtable,
144 withDetails=False,
145 readonly=False,
146 bodyMethod=None,
147 inner=True,
148 wrapMethod=None,
149 expanded=False,
150 withProv=True,
151 extraCls=None,
152 filterFunc=None,
153 combineMethod=None,
154 withN=True,
155 showEid=None,
156 ):
157 """Wrap the details of a specific table for this record into HTML.
159 Some of the parameters above will be passed to the initializers
160 of the detail record objects, others to their `wrap` method.
162 Parameters
163 ----------
164 dtable: string
165 The name of the detail table
166 withDetails, readonly, bodyMethod: mixed
167 See `control.record.Record`
168 inner, wrapMethod, withProv, extraCls: mixed
169 See `control.record.Record.wrap`.
170 expanded: boolean
171 Whether to expand all details in this detail table.
172 If True, the expanded details will not get a collapse control.
173 filterFunc: function, optional `None`
174 You can optionally filter the detail records.
175 combineMethod: function, optional `None`
176 After getting the HTML for individual records, you can
177 instruct to reorder/restructure those representations.
178 withN: boolean, optional `True`
179 Whether to present the number of detail records
180 showEid: ObjectId
181 Id of the detail record that should be initially opened.
183 Returns
184 -------
185 string(html)
186 """
188 details = self.details
190 (dtableObj, drecordsAll) = G(details, dtable, default=(None, []))
191 if not dtableObj: 191 ↛ 192line 191 didn't jump to line 192, because the condition on line 191 was never true
192 return E
194 drecords = [
195 drecord
196 for drecord in drecordsAll
197 if filterFunc is None or filterFunc(drecord)
198 ]
200 nRecords = len(drecords)
201 if nRecords == 0:
202 return E
204 (itemSingular, itemPlural) = dtableObj.itemLabels
205 itemLabel = itemSingular if nRecords == 1 else itemPlural
207 nRep = H.div(f"""{nRecords} {itemLabel}""", cls="stats")
209 drecordReps = []
210 for drecord in drecords:
211 show = showEid == str(G(drecord, N._id))
212 drecordReps.append(
213 dtableObj.record(
214 record=drecord,
215 readonly=readonly,
216 bodyMethod=bodyMethod,
217 withDetails=withDetails or show,
218 ).wrap(
219 inner=inner,
220 wrapMethod=wrapMethod,
221 withProv=withProv,
222 expanded=0 if expanded else 1 if show else -1,
223 )
224 )
225 if combineMethod: 225 ↛ 226line 225 didn't jump to line 226, because the condition on line 225 was never true
226 drecordReps = combineMethod(drecordReps)
228 innerCls = " inner" if inner else E
229 return H.div(
230 [nRep if withN else E] + drecordReps,
231 cls=f"record-details{innerCls} {extraCls}",
232 )
234 @staticmethod
235 def mustShow(table, kwargs):
236 """Determines the record id specified by `showTable` and `showEid` in `kwargs`.
238 "kwargs" may contain the keys `showTable` and `showEid`.
239 We want the value of `showEid`, but only if the value of `showTable` matches
240 `table`.
242 !!! hint
243 We need this when we have just inserted a detail record and want to
244 navigate to the master record with the new detail record in an
245 expanded state.
246 """
248 return G(kwargs, N.showEid) if G(kwargs, N.showTable) == table else None