Hide keyboard shortcuts

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"""Types of values in value tables.""" 

2 

3from control.utils import pick as G, E, NBSP 

4from control.html import HtmlElements as H 

5from config import Config as C, Names as N 

6from control.typ.related import Related, castObjectId 

7 

8CW = C.web 

9 

10MESSAGES = CW.messages 

11 

12FILTER_THRESHOLD = CW.filterThreshold 

13 

14QQ = H.icon(CW.unknown[N.generic]) 

15Qq = H.icon(CW.unknown[N.generic], asChar=True) 

16 

17 

18class ConversionError(Exception): 

19 pass 

20 

21 

22class Value(Related): 

23 """Type class for types with values in value tables.""" 

24 

25 widgetType = N.related 

26 

27 def __init__(self, context): 

28 """## Initialization 

29 

30 Store a handle to the Context singleton. 

31 

32 Parameters 

33 ---------- 

34 context: object 

35 See below. 

36 """ 

37 

38 self.context = context 

39 """*object* A `control.context.Context` singleton. 

40 """ 

41 

42 def fromStr(self, editVal, constrain=None, uid=None, eppn=None, extensible=False): 

43 """Convert a value to an object id by looking it up in a value table. 

44 

45 If the value is a singleton list, and if the value list is extensible, 

46 we insert the new value into the value table, and return the new id. 

47 

48 Otherwise, the value must be either: 

49 

50 * the string representation of id of a value 

51 * or a value in the relevant value table. 

52 

53 In all cases the MongoDb object id of that value is returned. 

54 

55 If a `constrain` is given only values in a subset defined by a constraint 

56 qualify. This happens when we look for score records that are bound to a 

57 criterion. 

58 

59 Parameters 

60 ---------- 

61 editVal: string 

62 The value as it has been sent from the client 

63 constrain: 

64 An additional constraint for the value. 

65 See `control.db.Db.getValueRecords`. 

66 """ 

67 

68 if not editVal: 

69 return None 

70 

71 context = self.context 

72 db = context.db 

73 table = self.name 

74 

75 valType = type(editVal) 

76 valuesInv = ( 

77 getattr(db, f"""{table}Inv""", {}) 

78 if constrain is None 

79 else db.getValueInv(table, constrain) 

80 ) 

81 if valType is list or valType is tuple: 

82 if extensible and editVal: 

83 editVal = editVal[0] 

84 if editVal in valuesInv: 84 ↛ 85line 84 didn't jump to line 85, because the condition on line 84 was never true

85 return valuesInv[editVal] 

86 fieldName = N.rep if extensible is True else extensible 

87 field = {fieldName: editVal} 

88 return db.insertItem(table, uid, eppn, True, **field) 

89 raise ConversionError 

90 

91 values = ( 

92 getattr(db, table, {}) 

93 if constrain is None 

94 else db.getValueIds(table, constrain) 

95 ) 

96 valId = castObjectId(editVal) 

97 if valId is None: 

98 valId = G(valuesInv, editVal) 

99 if valId not in values: 

100 raise ConversionError 

101 return valId 

102 

103 def toEdit(self, val): 

104 return val 

105 

106 def toOrig(self, val): 

107 return val if val is None else str(val) 

108 

109 def widget(self, val, multiple, extensible, constrain): 

110 context = self.context 

111 db = context.db 

112 table = self.name 

113 

114 if table == N.permissionGroup: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true

115 auth = context.auth 

116 user = auth.user 

117 group = G(user, N.group) 

118 groupRep = G(G(db.permissionGroup, group), N.rep) 

119 else: 

120 groupRep = None 

121 

122 valueRecords = db.getValueRecords(table, constrain=constrain, upper=groupRep) 

123 

124 filterControl = ( 

125 [ 

126 H.input( 

127 E, 

128 type=N.text, 

129 placeholder=G(MESSAGES, N.filter, default=E), 

130 cls="wfilter", 

131 ), 

132 H.iconx(N.add, cls="small wfilter add", title="add value") 

133 if extensible 

134 else E, 

135 H.iconx(N.clear, cls="small wfilter clear", title="clear filter"), 

136 ] 

137 if len(valueRecords) > FILTER_THRESHOLD 

138 else [] 

139 ) 

140 atts = dict( 

141 markup=True, 

142 clickable=True, 

143 multiple=multiple, 

144 active=val, 

145 hideInActual=True, 

146 hideBlockedUsers=True, 

147 ) 

148 results = (self.title(record=record, **atts) for record in valueRecords) 

149 return H.div( 

150 filterControl 

151 + [ 

152 formatted 

153 for (text, formatted) in ( 

154 ([] if multiple else [self.title(record={}, **atts)]) 

155 + ( 

156 sorted( 

157 results, 

158 key=lambda x: x[0].lower(), 

159 ) 

160 if type(valueRecords) is tuple 

161 else list(results) 

162 ) 

163 ) 

164 ], 

165 cls="wvalue", 

166 ) 

167 

168 def title( 

169 self, 

170 eid=None, 

171 record=None, 

172 markup=False, 

173 clickable=False, 

174 multiple=False, 

175 active=None, 

176 hideInActual=False, 

177 hideBlockedUsers=False, 

178 **kwargs, 

179 ): 

180 if record is None and eid is None: 

181 return None if markup is None else (QQ, QQ) if markup else Qq 

182 

183 table = self.name 

184 

185 if record is None: 

186 context = self.context 

187 record = context.getItem(table, eid) 

188 

189 titleStr = self.titleStr(record, markup=markup, **kwargs) 

190 titleHint = self.titleHint(record) 

191 

192 if markup: 

193 if eid is None: 

194 eid = G(record, N._id) 

195 

196 isActive = eid in (active or []) if multiple else eid == active 

197 baseCls = ( 

198 ("button " if multiple or not isActive else "label ") 

199 if clickable 

200 else "tag " 

201 ) 

202 activeCls = "active " if isActive else E 

203 inActualCls = self.inActualCls(record=record) 

204 hidden = ( 

205 hideInActual 

206 and inActualCls 

207 and not isActive 

208 or hideBlockedUsers 

209 and table == N.user 

210 and not G(record, N.mayLogin) 

211 ) 

212 if hidden: 212 ↛ 213line 212 didn't jump to line 213, because the condition on line 212 was never true

213 return (E, E) 

214 atts = dict(cls=f"{baseCls}{activeCls}medium {inActualCls}") 

215 if clickable and eid is not None: 

216 atts[N.eid] = str(eid) 

217 

218 if titleHint: 

219 atts[N.title] = titleHint 

220 

221 titleIcon = ( 

222 (NBSP + H.icon(N.cross if isActive else N.add, cls="small")) 

223 if multiple 

224 else E 

225 ) 

226 

227 titleFormatted = H.span( 

228 [titleStr, titleIcon], 

229 lab=titleStr.lower(), 

230 **atts, 

231 ) 

232 return (titleStr, titleFormatted) 

233 else: 

234 return titleStr