rev |
line source |
bsw/jbe@0
|
1 Member = mondelefant.new_class()
|
bsw/jbe@0
|
2 Member.table = 'member'
|
bsw/jbe@0
|
3
|
jbe@1232
|
4 local function secret_token()
|
jbe@1232
|
5 local parts = {}
|
jbe@1232
|
6 for i = 1, 5 do
|
jbe@1232
|
7 parts[#parts+1] = multirand.string(5, "23456789bcdfghjkmnpqrstvwxyz")
|
jbe@1232
|
8 end
|
jbe@1232
|
9 return (table.concat(parts, "-"))
|
jbe@1232
|
10 end
|
jbe@1232
|
11
|
bsw/jbe@0
|
12 Member:add_reference{
|
bsw@9
|
13 mode = "1m",
|
bsw@9
|
14 to = "MemberHistory",
|
bsw@9
|
15 this_key = 'id',
|
bsw@9
|
16 that_key = 'member_id',
|
bsw@9
|
17 ref = 'history_entries',
|
bsw@9
|
18 back_ref = 'member'
|
bsw@9
|
19 }
|
bsw@9
|
20
|
bsw@9
|
21 Member:add_reference{
|
bsw/jbe@4
|
22 mode = '1m',
|
bsw@2
|
23 to = "MemberImage",
|
bsw@2
|
24 this_key = 'id',
|
bsw@2
|
25 that_key = 'member_id',
|
bsw/jbe@4
|
26 ref = 'images',
|
bsw@2
|
27 back_ref = 'member'
|
bsw@2
|
28 }
|
bsw@2
|
29
|
bsw@2
|
30 Member:add_reference{
|
bsw/jbe@0
|
31 mode = '1m',
|
bsw/jbe@0
|
32 to = "Contact",
|
bsw/jbe@0
|
33 this_key = 'id',
|
bsw/jbe@0
|
34 that_key = 'member_id',
|
bsw/jbe@0
|
35 ref = 'contacts',
|
bsw/jbe@0
|
36 back_ref = 'member',
|
bsw/jbe@0
|
37 default_order = '"other_member_id"'
|
bsw/jbe@0
|
38 }
|
bsw/jbe@0
|
39
|
bsw/jbe@0
|
40 Member:add_reference{
|
bsw/jbe@0
|
41 mode = '1m',
|
bsw/jbe@0
|
42 to = "Contact",
|
bsw/jbe@0
|
43 this_key = 'id',
|
bsw/jbe@0
|
44 that_key = 'member_id',
|
bsw/jbe@0
|
45 ref = 'foreign_contacts',
|
bsw/jbe@0
|
46 back_ref = 'other_member',
|
bsw/jbe@0
|
47 default_order = '"member_id"'
|
bsw/jbe@0
|
48 }
|
bsw/jbe@0
|
49
|
bsw/jbe@0
|
50 Member:add_reference{
|
bsw/jbe@0
|
51 mode = '1m',
|
bsw/jbe@0
|
52 to = "Session",
|
bsw/jbe@0
|
53 this_key = 'id',
|
bsw/jbe@0
|
54 that_key = 'member_id',
|
bsw/jbe@0
|
55 ref = 'sessions',
|
bsw/jbe@0
|
56 back_ref = 'member',
|
bsw/jbe@0
|
57 default_order = '"ident"'
|
bsw/jbe@0
|
58 }
|
bsw/jbe@0
|
59
|
bsw/jbe@0
|
60 Member:add_reference{
|
bsw/jbe@0
|
61 mode = '1m',
|
bsw/jbe@0
|
62 to = "Draft",
|
bsw/jbe@0
|
63 this_key = 'id',
|
bsw/jbe@0
|
64 that_key = 'author_id',
|
bsw/jbe@0
|
65 ref = 'drafts',
|
bsw/jbe@0
|
66 back_ref = 'author',
|
bsw/jbe@0
|
67 default_order = '"id"'
|
bsw/jbe@0
|
68 }
|
bsw/jbe@0
|
69
|
bsw/jbe@0
|
70 Member:add_reference{
|
bsw/jbe@0
|
71 mode = '1m',
|
bsw/jbe@0
|
72 to = "Suggestion",
|
bsw/jbe@0
|
73 this_key = 'id',
|
bsw/jbe@0
|
74 that_key = 'author_id',
|
bsw/jbe@0
|
75 ref = 'suggestions',
|
bsw/jbe@0
|
76 back_ref = 'author',
|
bsw/jbe@0
|
77 default_order = '"id"'
|
bsw/jbe@0
|
78 }
|
bsw/jbe@0
|
79
|
bsw/jbe@0
|
80 Member:add_reference{
|
bsw/jbe@0
|
81 mode = '1m',
|
bsw/jbe@0
|
82 to = "Membership",
|
bsw/jbe@0
|
83 this_key = 'id',
|
bsw/jbe@0
|
84 that_key = 'member_id',
|
bsw/jbe@0
|
85 ref = 'memberships',
|
bsw/jbe@0
|
86 back_ref = 'member',
|
bsw/jbe@0
|
87 default_order = '"area_id"'
|
bsw/jbe@0
|
88 }
|
bsw/jbe@0
|
89
|
bsw/jbe@0
|
90 Member:add_reference{
|
bsw/jbe@0
|
91 mode = '1m',
|
bsw/jbe@0
|
92 to = "Interest",
|
bsw/jbe@0
|
93 this_key = 'id',
|
bsw/jbe@0
|
94 that_key = 'member_id',
|
bsw/jbe@0
|
95 ref = 'interests',
|
bsw/jbe@0
|
96 back_ref = 'member',
|
bsw/jbe@0
|
97 default_order = '"id"'
|
bsw/jbe@0
|
98 }
|
bsw/jbe@0
|
99
|
bsw/jbe@0
|
100 Member:add_reference{
|
bsw/jbe@0
|
101 mode = '1m',
|
bsw/jbe@0
|
102 to = "Initiator",
|
bsw/jbe@0
|
103 this_key = 'id',
|
bsw/jbe@0
|
104 that_key = 'member_id',
|
bsw/jbe@0
|
105 ref = 'initiators',
|
bsw@10
|
106 back_ref = 'member'
|
bsw/jbe@0
|
107 }
|
bsw/jbe@0
|
108
|
bsw/jbe@0
|
109 Member:add_reference{
|
bsw/jbe@0
|
110 mode = '1m',
|
bsw/jbe@0
|
111 to = "Supporter",
|
bsw/jbe@0
|
112 this_key = 'id',
|
bsw/jbe@0
|
113 that_key = 'member_id',
|
bsw/jbe@0
|
114 ref = 'supporters',
|
bsw@2
|
115 back_ref = 'member'
|
bsw/jbe@0
|
116 }
|
bsw/jbe@0
|
117
|
bsw/jbe@0
|
118 Member:add_reference{
|
bsw/jbe@0
|
119 mode = '1m',
|
bsw/jbe@0
|
120 to = "Opinion",
|
bsw/jbe@0
|
121 this_key = 'id',
|
bsw/jbe@0
|
122 that_key = 'member_id',
|
bsw/jbe@0
|
123 ref = 'opinions',
|
bsw/jbe@0
|
124 back_ref = 'member',
|
bsw/jbe@0
|
125 default_order = '"id"'
|
bsw/jbe@0
|
126 }
|
bsw/jbe@0
|
127
|
bsw/jbe@0
|
128 Member:add_reference{
|
bsw/jbe@0
|
129 mode = '1m',
|
bsw/jbe@0
|
130 to = "Delegation",
|
bsw/jbe@0
|
131 this_key = 'id',
|
bsw/jbe@0
|
132 that_key = 'truster_id',
|
bsw/jbe@0
|
133 ref = 'outgoing_delegations',
|
bsw/jbe@0
|
134 back_ref = 'truster',
|
bsw@1045
|
135 -- default_order = '"id"'
|
bsw/jbe@0
|
136 }
|
bsw/jbe@0
|
137
|
bsw/jbe@0
|
138 Member:add_reference{
|
bsw/jbe@0
|
139 mode = '1m',
|
bsw/jbe@0
|
140 to = "Delegation",
|
bsw/jbe@0
|
141 this_key = 'id',
|
bsw/jbe@0
|
142 that_key = 'trustee_id',
|
bsw/jbe@0
|
143 ref = 'incoming_delegations',
|
bsw/jbe@0
|
144 back_ref = 'trustee',
|
bsw@1045
|
145 -- default_order = '"id"'
|
bsw/jbe@0
|
146 }
|
bsw/jbe@0
|
147
|
bsw/jbe@0
|
148 Member:add_reference{
|
bsw/jbe@0
|
149 mode = '1m',
|
bsw/jbe@0
|
150 to = "DirectVoter",
|
bsw/jbe@0
|
151 this_key = 'id',
|
bsw/jbe@0
|
152 that_key = 'member_id',
|
bsw/jbe@0
|
153 ref = 'direct_voter',
|
bsw/jbe@0
|
154 back_ref = 'member',
|
bsw/jbe@0
|
155 default_order = '"issue_id"'
|
bsw/jbe@0
|
156 }
|
bsw/jbe@0
|
157
|
bsw/jbe@0
|
158 Member:add_reference{
|
bsw/jbe@0
|
159 mode = '1m',
|
bsw/jbe@0
|
160 to = "Vote",
|
bsw/jbe@0
|
161 this_key = 'id',
|
bsw/jbe@0
|
162 that_key = 'member_id',
|
bsw/jbe@0
|
163 ref = 'vote',
|
bsw/jbe@0
|
164 back_ref = 'member',
|
bsw/jbe@0
|
165 default_order = '"issue_id", "initiative_id"'
|
bsw/jbe@0
|
166 }
|
bsw/jbe@0
|
167
|
bsw/jbe@0
|
168 Member:add_reference{
|
bsw/jbe@1309
|
169 mode = '11',
|
bsw/jbe@1309
|
170 to = "MemberProfile",
|
bsw/jbe@1309
|
171 this_key = 'id',
|
bsw/jbe@1309
|
172 that_key = 'member_id',
|
bsw/jbe@1309
|
173 ref = 'profile',
|
bsw/jbe@1309
|
174 back_ref = 'member'
|
bsw/jbe@1309
|
175 }
|
bsw/jbe@1309
|
176
|
bsw/jbe@1309
|
177 Member:add_reference{
|
bsw/jbe@1309
|
178 mode = '11',
|
bsw/jbe@1309
|
179 to = "MemberSettings",
|
bsw/jbe@1309
|
180 this_key = 'id',
|
bsw/jbe@1309
|
181 that_key = 'member_id',
|
bsw/jbe@1309
|
182 ref = 'settings',
|
bsw/jbe@1309
|
183 back_ref = 'member'
|
bsw/jbe@1309
|
184 }
|
bsw/jbe@1309
|
185
|
bsw/jbe@1309
|
186 Member:add_reference{
|
bsw/jbe@0
|
187 mode = 'mm',
|
bsw/jbe@0
|
188 to = "Member",
|
bsw/jbe@0
|
189 this_key = 'id',
|
bsw/jbe@0
|
190 that_key = 'id',
|
bsw/jbe@0
|
191 connected_by_table = 'contact',
|
bsw/jbe@0
|
192 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
193 connected_by_that_key = 'other_member_id',
|
bsw/jbe@0
|
194 ref = 'saved_members',
|
bsw/jbe@0
|
195 }
|
bsw/jbe@0
|
196
|
bsw/jbe@0
|
197 Member:add_reference{
|
bsw/jbe@0
|
198 mode = 'mm',
|
bsw/jbe@0
|
199 to = "Member",
|
bsw/jbe@0
|
200 this_key = 'id',
|
bsw/jbe@0
|
201 that_key = 'id',
|
bsw/jbe@0
|
202 connected_by_table = 'contact',
|
bsw/jbe@0
|
203 connected_by_this_key = 'other_member_id',
|
bsw/jbe@0
|
204 connected_by_that_key = 'member_id',
|
bsw/jbe@0
|
205 ref = 'saved_by_members',
|
bsw/jbe@0
|
206 }
|
bsw/jbe@0
|
207
|
bsw/jbe@0
|
208 Member:add_reference{
|
bsw/jbe@0
|
209 mode = 'mm',
|
bsw@281
|
210 to = "Unit",
|
bsw@281
|
211 this_key = 'id',
|
bsw@281
|
212 that_key = 'id',
|
bsw@281
|
213 connected_by_table = 'privilege',
|
bsw@281
|
214 connected_by_this_key = 'member_id',
|
bsw@281
|
215 connected_by_that_key = 'unit_id',
|
bsw@281
|
216 ref = 'units'
|
bsw@281
|
217 }
|
bsw@281
|
218
|
bsw@281
|
219 Member:add_reference{
|
bsw@281
|
220 mode = 'mm',
|
bsw/jbe@0
|
221 to = "Area",
|
bsw/jbe@0
|
222 this_key = 'id',
|
bsw/jbe@0
|
223 that_key = 'id',
|
bsw/jbe@0
|
224 connected_by_table = 'membership',
|
bsw/jbe@0
|
225 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
226 connected_by_that_key = 'area_id',
|
bsw/jbe@0
|
227 ref = 'areas'
|
bsw/jbe@0
|
228 }
|
bsw/jbe@0
|
229
|
bsw/jbe@0
|
230 Member:add_reference{
|
bsw/jbe@0
|
231 mode = 'mm',
|
bsw/jbe@0
|
232 to = "Issue",
|
bsw/jbe@0
|
233 this_key = 'id',
|
bsw/jbe@0
|
234 that_key = 'id',
|
bsw/jbe@0
|
235 connected_by_table = 'interest',
|
bsw/jbe@0
|
236 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
237 connected_by_that_key = 'issue_id',
|
bsw/jbe@0
|
238 ref = 'issues'
|
bsw/jbe@0
|
239 }
|
bsw/jbe@0
|
240
|
bsw/jbe@0
|
241 Member:add_reference{
|
bsw/jbe@0
|
242 mode = 'mm',
|
bsw/jbe@0
|
243 to = "Initiative",
|
bsw/jbe@0
|
244 this_key = 'id',
|
bsw/jbe@0
|
245 that_key = 'id',
|
bsw/jbe@0
|
246 connected_by_table = 'initiator',
|
bsw/jbe@0
|
247 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
248 connected_by_that_key = 'initiative_id',
|
bsw/jbe@0
|
249 ref = 'initiated_initiatives'
|
bsw/jbe@0
|
250 }
|
bsw/jbe@0
|
251
|
bsw/jbe@0
|
252 Member:add_reference{
|
bsw/jbe@0
|
253 mode = 'mm',
|
bsw/jbe@0
|
254 to = "Initiative",
|
bsw/jbe@0
|
255 this_key = 'id',
|
bsw/jbe@0
|
256 that_key = 'id',
|
bsw/jbe@0
|
257 connected_by_table = 'supporter',
|
bsw/jbe@0
|
258 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
259 connected_by_that_key = 'initiative_id',
|
bsw/jbe@0
|
260 ref = 'supported_initiatives'
|
bsw/jbe@0
|
261 }
|
bsw/jbe@0
|
262
|
bsw@193
|
263 function Member:build_selector(args)
|
bsw@193
|
264 local selector = self:new_selector()
|
bsw@193
|
265 if args.active ~= nil then
|
bsw@193
|
266 selector:add_where{ "member.active = ?", args.active }
|
bsw@193
|
267 end
|
bsw@581
|
268 if args.locked ~= nil then
|
bsw@581
|
269 selector:add_where{ "member.locked = ?", args.locked }
|
bsw@581
|
270 end
|
bsw@199
|
271 if args.is_contact_of_member_id then
|
bsw@199
|
272 selector:join("contact", "__model_member__contact", "member.id = __model_member__contact.other_member_id")
|
bsw@199
|
273 selector:add_where{ "__model_member__contact.member_id = ?", args.is_contact_of_member_id }
|
bsw@199
|
274 end
|
bsw@297
|
275 if args.voting_right_for_unit_id then
|
bsw@299
|
276 selector:join("privilege", "__model_member__privilege", { "member.id = __model_member__privilege.member_id AND __model_member__privilege.voting_right AND __model_member__privilege.unit_id = ?", args.voting_right_for_unit_id })
|
bsw@297
|
277 end
|
bsw@581
|
278 if args.admin_search then
|
bsw@581
|
279 local search_string = "%" .. args.admin_search .. "%"
|
bsw@581
|
280 selector:add_where{ "member.identification ILIKE ? OR member.name ILIKE ?", search_string, search_string }
|
bsw@581
|
281 end
|
bsw@193
|
282 if args.order then
|
bsw@193
|
283 if args.order == "id" then
|
bsw@193
|
284 selector:add_order_by("id")
|
bsw@581
|
285 elseif args.order == "identification" then
|
bsw@581
|
286 selector:add_order_by("identification")
|
bsw@193
|
287 elseif args.order == "name" then
|
bsw@193
|
288 selector:add_order_by("name")
|
bsw@193
|
289 else
|
bsw@193
|
290 error("invalid order")
|
bsw@193
|
291 end
|
bsw@193
|
292 end
|
bsw@193
|
293 return selector
|
bsw@193
|
294 end
|
bsw@193
|
295
|
bsw@929
|
296 function Member:lockForReference()
|
bsw@929
|
297 self.get_db_conn().query("LOCK TABLE " .. self:get_qualified_table() .. " IN ROW SHARE MODE")
|
bsw@929
|
298 end
|
bsw@929
|
299
|
bsw@1071
|
300
|
bsw@1071
|
301 function Member:get_all_by_authority(authority)
|
bsw@1071
|
302
|
bsw@1071
|
303 local members = Member:new_selector()
|
bsw@1071
|
304 :add_where{ "authority = ?", authority }
|
bsw@1074
|
305 :add_field("authority_uid")
|
bsw@1071
|
306 :exec()
|
bsw@1071
|
307
|
bsw@1071
|
308 return members
|
bsw@1071
|
309 end
|
bsw@1071
|
310
|
bsw/jbe@0
|
311 function Member.object:set_password(password)
|
bsw@865
|
312 trace.disable()
|
bsw@905
|
313
|
bsw@905
|
314 local hash_prefix
|
bsw@905
|
315 local salt_length
|
bsw@905
|
316
|
bsw@905
|
317 local function rounds()
|
bsw@905
|
318 return multirand.integer(
|
bsw@905
|
319 config.password_hash_min_rounds,
|
bsw@905
|
320 config.password_hash_max_rounds
|
bsw@905
|
321 )
|
bsw@905
|
322 end
|
bsw@905
|
323
|
bsw@905
|
324 if config.password_hash_algorithm == "crypt_md5" then
|
bsw@905
|
325 hash_prefix = "$1$"
|
bsw@905
|
326 salt_length = 8
|
bsw@905
|
327
|
bsw@905
|
328 elseif config.password_hash_algorithm == "crypt_sha256" then
|
bsw@905
|
329 hash_prefix = "$5$rounds=" .. rounds() .. "$"
|
bsw@905
|
330 salt_length = 16
|
bsw@905
|
331
|
bsw@905
|
332 elseif config.password_hash_algorithm == "crypt_sha512" then
|
bsw@905
|
333 hash_prefix = "$6$rounds=" .. rounds() .. "$"
|
bsw@905
|
334 salt_length = 16
|
bsw@905
|
335
|
bsw@905
|
336 else
|
bsw@905
|
337 error("Unknown hash algorithm selected in configuration")
|
bsw@905
|
338
|
bsw@905
|
339 end
|
bsw@906
|
340
|
bsw@906
|
341 hash_prefix = hash_prefix .. multirand.string(
|
bsw@906
|
342 salt_length,
|
bsw@906
|
343 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"
|
bsw@906
|
344 )
|
bsw@905
|
345
|
bsw@906
|
346 local hash = extos.crypt(password, hash_prefix)
|
bsw@905
|
347
|
bsw@905
|
348 if not hash or hash:sub(1, #hash_prefix) ~= hash_prefix then
|
bsw@905
|
349 error("Password hashing algorithm failed")
|
bsw@905
|
350 end
|
bsw@905
|
351
|
bsw/jbe@0
|
352 self.password = hash
|
bsw@1231
|
353 self.password_reset_secret = nil
|
bsw@1231
|
354 self.password_reset_secret_expiry = nil
|
bsw/jbe@0
|
355 end
|
bsw/jbe@0
|
356
|
bsw/jbe@0
|
357 function Member.object:check_password(password)
|
bsw/jbe@0
|
358 if type(password) == "string" and type(self.password) == "string" then
|
bsw@728
|
359 return extos.crypt(password, self.password) == self.password
|
bsw/jbe@0
|
360 else
|
bsw/jbe@0
|
361 return false
|
bsw/jbe@0
|
362 end
|
bsw/jbe@0
|
363 end
|
bsw/jbe@0
|
364
|
bsw@905
|
365 function Member.object_get:password_hash_needs_update()
|
bsw@905
|
366
|
bsw@905
|
367 if self.password == nil then
|
bsw@905
|
368 return nil
|
bsw@905
|
369 end
|
bsw@905
|
370
|
bsw@905
|
371 local function check_rounds(rounds)
|
bsw@905
|
372 if rounds then
|
bsw@905
|
373 rounds = tonumber(rounds)
|
bsw@905
|
374 if
|
bsw@905
|
375 rounds >= config.password_hash_min_rounds and
|
bsw@905
|
376 rounds <= config.password_hash_max_rounds
|
bsw@905
|
377 then
|
bsw@905
|
378 return false
|
bsw@905
|
379 end
|
bsw@905
|
380 end
|
bsw@905
|
381 return true
|
bsw@905
|
382 end
|
bsw@905
|
383
|
bsw@905
|
384 if config.password_hash_algorithm == "crypt_md5" then
|
bsw@905
|
385
|
bsw@905
|
386 return self.password:sub(1,3) ~= "$1$"
|
bsw@905
|
387
|
bsw@905
|
388 elseif config.password_hash_algorithm == "crypt_sha256" then
|
bsw@905
|
389
|
bsw@905
|
390 return check_rounds(self.password:match("^%$5%$rounds=([1-9][0-9]*)%$"))
|
bsw@905
|
391
|
bsw@905
|
392 elseif config.password_hash_algorithm == "crypt_sha512" then
|
bsw@905
|
393
|
bsw@905
|
394 return check_rounds(self.password:match("^%$6%$rounds=([1-9][0-9]*)%$"))
|
bsw@905
|
395
|
bsw@905
|
396 else
|
bsw@905
|
397 error("Unknown hash algorithm selected in configuration")
|
bsw@905
|
398
|
bsw@905
|
399 end
|
bsw@905
|
400
|
bsw@905
|
401 end
|
bsw@905
|
402
|
bsw/jbe@0
|
403 function Member.object_get:published_contacts()
|
bsw/jbe@0
|
404 return Member:new_selector()
|
bsw/jbe@0
|
405 :join('"contact"', nil, '"contact"."other_member_id" = "member"."id"')
|
bsw/jbe@0
|
406 :add_where{ '"contact"."member_id" = ?', self.id }
|
bsw/jbe@0
|
407 :add_where("public")
|
bsw/jbe@0
|
408 :exec()
|
bsw/jbe@0
|
409 end
|
bsw/jbe@0
|
410
|
bsw/jbe@0
|
411 function Member:by_login_and_password(login, password)
|
bsw@1071
|
412
|
bsw@1071
|
413 local function prepare_login_selector()
|
bsw@1071
|
414 local selector = self:new_selector()
|
bsw@1071
|
415 selector:add_field({ "now() > COALESCE(last_delegation_check, activated) + ?::interval", config.check_delegations_interval_hard }, "needs_delegation_check_hard")
|
bsw@1071
|
416 selector:add_where('NOT "locked"')
|
bsw@1071
|
417 selector:optional_object_mode()
|
bsw@1071
|
418 return selector
|
bsw@1071
|
419 end
|
bsw@1071
|
420
|
bsw@1071
|
421 local function do_local_login()
|
bsw@1071
|
422 local selector = prepare_login_selector()
|
bsw@1071
|
423 selector:add_where{'"login" = ?', login }
|
bsw@1071
|
424 local member = selector:exec()
|
bsw@1071
|
425 if member and member:check_password(password) then
|
bsw@1071
|
426 return member
|
bsw@1071
|
427 else
|
bsw@1071
|
428 return nil
|
bsw@1071
|
429 end
|
bsw/jbe@0
|
430 end
|
bsw@1071
|
431
|
bsw@1071
|
432 if config.ldap.member then
|
bsw@1071
|
433
|
bsw@1071
|
434 -- Let's check the users credentials against the LDAP
|
bsw@1071
|
435 local ldap_entry, ldap_err = ldap.check_credentials(login, password)
|
bsw@1071
|
436
|
bsw@1071
|
437 -- Is the user already registered as member?
|
bsw@1071
|
438 local uid
|
bsw@1071
|
439 local selector = prepare_login_selector()
|
bsw@1071
|
440
|
bsw@1071
|
441 -- Get login name from LDAP entry
|
bsw@1071
|
442 if ldap_entry then
|
bsw@1071
|
443 uid = config.ldap.member.uid_map(ldap_entry)
|
bsw@1074
|
444 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", uid }
|
bsw@1071
|
445
|
bsw@1071
|
446 -- or build it from the login
|
bsw@1071
|
447 else
|
bsw@1071
|
448 login = config.ldap.member.login_normalizer(login)
|
bsw@1074
|
449 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", login }
|
bsw@1071
|
450 end
|
bsw@1071
|
451
|
bsw@1071
|
452 local member = selector:exec()
|
bsw@1071
|
453 -- The member is already registered
|
bsw@1071
|
454 if member then
|
bsw@1071
|
455
|
bsw@1071
|
456 -- The credentials entered by the user are invalid
|
bsw@1071
|
457 if ldap_err == "invalid_credentials" then
|
bsw@1071
|
458
|
bsw@1071
|
459 -- Check if the user tried a cached password (which is invalid now)
|
bsw@1071
|
460 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
461 member.password = nil
|
bsw@1071
|
462 member:save()
|
bsw@1071
|
463 end
|
bsw@1071
|
464
|
bsw@1071
|
465 -- Try a regular login
|
bsw@1071
|
466 return do_local_login()
|
bsw@1071
|
467
|
bsw@1071
|
468 end
|
bsw@1071
|
469
|
bsw@1071
|
470 -- The credentials were accepted by the LDAP server and no error occured
|
bsw@1071
|
471 if ldap_entry and not ldap_err then
|
bsw@1071
|
472
|
bsw@1071
|
473 -- Cache the password (if feature enabled)
|
bsw@1071
|
474 if config.ldap.member.cache_passwords and not member:check_password(password) then
|
bsw@1071
|
475 member:set_password(password)
|
bsw@1071
|
476 end
|
bsw@1071
|
477
|
bsw@1071
|
478 -- update the member attributes and privileges from LDAP
|
bsw@1071
|
479 local ldap_conn, ldap_err, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
480 if not err then
|
bsw@1071
|
481 local err = member:try_save()
|
bsw@1071
|
482 if err then
|
bsw@1071
|
483 return nil, "member_save_error", err
|
bsw@1071
|
484 end
|
bsw@1071
|
485 local succes, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
486 if err then
|
bsw@1071
|
487 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
488 end
|
bsw@1071
|
489 return member
|
bsw@1071
|
490 end
|
bsw@1071
|
491
|
bsw@1071
|
492 end
|
bsw@1071
|
493
|
bsw@1071
|
494 -- Some kind of LDAP error happened, if cached password are enabled,
|
bsw@1071
|
495 -- check user credentials against the cache
|
bsw@1071
|
496 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
497
|
bsw@1071
|
498 -- return the successfully logged in member
|
bsw@1071
|
499 return member
|
bsw@1071
|
500
|
bsw@1071
|
501 end
|
bsw@1071
|
502
|
bsw@1071
|
503 -- The member is not registered
|
bsw@1071
|
504 elseif config.ldap.member.registration and ldap_entry and not ldap_err then
|
bsw@1071
|
505 -- Automatic registration ("auto")
|
bsw@1071
|
506 if config.ldap.member.registration == "auto" then
|
bsw@1071
|
507 member = Member:new()
|
bsw@1071
|
508 member.authority = "ldap"
|
bsw@1071
|
509 local ldap_login
|
bsw@1071
|
510 if config.ldap.member.cache_passwords then
|
bsw@1071
|
511 if config.ldap.member.login_normalizer then
|
bsw@1071
|
512 ldap_login = config.ldap.member.login_normalizer(login)
|
bsw@1071
|
513 else
|
bsw@1071
|
514 ldap_login = login
|
bsw@1071
|
515 end
|
bsw@1071
|
516 end
|
bsw@1071
|
517 -- TODO change this when SQL layers supports hstore
|
bsw@1074
|
518 member.authority_uid = uid
|
bsw@1074
|
519 member.authority_login = ldap_login
|
bsw@1071
|
520 member.activated = "now"
|
bsw@1071
|
521 member.last_activity = "now"
|
bsw@1071
|
522 if config.ldap.member.cache_passwords then
|
bsw@1071
|
523 member:set_password(password)
|
bsw@1071
|
524 end
|
bsw@1071
|
525 local ldap_conn, ldap_err, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
526 if not err then
|
bsw@1071
|
527 local err = member:try_save()
|
bsw@1071
|
528 if err then
|
bsw@1071
|
529 return nil, "member_save_error", err
|
bsw@1071
|
530 end
|
bsw@1071
|
531 local success, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
532 if err then
|
bsw@1071
|
533 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
534 end
|
bsw@1071
|
535 return member
|
bsw@1071
|
536 end
|
bsw@1071
|
537
|
bsw@1071
|
538 -- No automatic registration
|
bsw@1071
|
539 else
|
bsw@1071
|
540 return nil, "ldap_credentials_valid_but_no_member", uid
|
bsw@1071
|
541 end
|
bsw@1071
|
542 end
|
bsw@1071
|
543
|
bsw@1071
|
544 end
|
bsw@1071
|
545
|
bsw@1071
|
546 return do_local_login()
|
bsw@1071
|
547
|
bsw/jbe@0
|
548 end
|
bsw/jbe@0
|
549
|
bsw/jbe@1309
|
550 function Member:by_ids(ids)
|
bsw/jbe@1309
|
551 local selector = self:new_selector()
|
bsw/jbe@1309
|
552 selector:add_where{'"id" IN ($)', { ids } }
|
bsw/jbe@1309
|
553 return selector:exec()
|
bsw/jbe@1309
|
554 end
|
bsw/jbe@1309
|
555
|
bsw/jbe@5
|
556 function Member:by_login(login)
|
bsw/jbe@5
|
557 local selector = self:new_selector()
|
bsw/jbe@5
|
558 selector:add_where{'"login" = ?', login }
|
bsw/jbe@5
|
559 selector:optional_object_mode()
|
bsw/jbe@5
|
560 return selector:exec()
|
bsw/jbe@5
|
561 end
|
bsw/jbe@5
|
562
|
bsw/jbe@5
|
563 function Member:by_name(name)
|
bsw/jbe@5
|
564 local selector = self:new_selector()
|
bsw/jbe@5
|
565 selector:add_where{'"name" = ?', name }
|
bsw/jbe@5
|
566 selector:optional_object_mode()
|
bsw/jbe@5
|
567 return selector:exec()
|
bsw/jbe@5
|
568 end
|
bsw/jbe@5
|
569
|
bsw@2
|
570 function Member:get_search_selector(search_string)
|
bsw/jbe@0
|
571 return self:new_selector()
|
bsw@2
|
572 :add_field( {'"highlight"("member"."name", ?)', search_string }, "name_highlighted")
|
bsw@1492
|
573 :add_where{ 'to_tsvector("member") @@ "plainto_tsquery"(?)', search_string }
|
bsw@362
|
574 :add_where("activated NOTNULL AND active")
|
bsw/jbe@0
|
575 end
|
bsw@2
|
576
|
bsw@1231
|
577 function Member.object:send_password_reset_mail()
|
bsw@1231
|
578 trace.disable()
|
bsw@1231
|
579 if not self.notify_email then
|
bsw@1231
|
580 return false
|
bsw@1231
|
581 end
|
jbe@1232
|
582 self.password_reset_secret = secret_token()
|
bsw@1231
|
583 local expiry = db:query("SELECT now() + '1 days'::interval as expiry", "object").expiry
|
bsw@1231
|
584 self.password_reset_secret_expiry = expiry
|
bsw@1231
|
585 self:save()
|
bsw@1231
|
586 local content = slot.use_temporary(function()
|
bsw@1231
|
587 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw@1231
|
588 slot.put(_"to reset your password please click on the following link:\n\n")
|
bsw@1231
|
589 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html?secret=" .. self.password_reset_secret .. "\n\n")
|
bsw@1231
|
590 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw@1231
|
591 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html\n\n")
|
bsw@1231
|
592 slot.put(_"On that page please enter the reset code:\n\n")
|
bsw@1231
|
593 slot.put(self.password_reset_secret .. "\n\n")
|
bsw@1231
|
594 end)
|
bsw@1231
|
595 local success = net.send_mail{
|
bsw@1231
|
596 envelope_from = config.mail_envelope_from,
|
bsw@1231
|
597 from = config.mail_from,
|
bsw@1231
|
598 reply_to = config.mail_reply_to,
|
bsw@1231
|
599 to = self.notify_email,
|
bsw@1231
|
600 subject = config.mail_subject_prefix .. _"Password reset request",
|
bsw@1231
|
601 content_type = "text/plain; charset=UTF-8",
|
bsw@1231
|
602 content = content
|
bsw@1231
|
603 }
|
bsw@1231
|
604 return success
|
bsw@1231
|
605 end
|
bsw@1231
|
606
|
bsw@388
|
607 function Member.object:send_invitation(template_file, subject)
|
bsw@286
|
608 trace.disable()
|
jbe@1232
|
609 self.invite_code = secret_token()
|
bsw@388
|
610 self:save()
|
bsw@388
|
611
|
bsw@388
|
612 local subject = subject
|
bsw@388
|
613 local content
|
bsw/jbe@1309
|
614 local baseurl = request.get_absolute_baseurl() .. "index/register.html"
|
bsw/jbe@1309
|
615 local url = baseurl .. "?skip=1&code=" .. self.invite_code
|
bsw@388
|
616 if template_file then
|
bsw@388
|
617 local fh = io.open(template_file, "r")
|
bsw@388
|
618 content = fh:read("*a")
|
bsw/jbe@1309
|
619 content = content:gsub("#{url}", url):gsub("#{baseurl}", baseurl):gsub("#{code}", self.invite_code)
|
bsw/jbe@1309
|
620 elseif config.invitation_mail then
|
bsw/jbe@1309
|
621 subject = config.invitation_mail.subject
|
bsw/jbe@1309
|
622 content = config.invitation_mail.content:gsub("#{url}", url):gsub("#{baseurl}", baseurl):gsub("#{code}", self.invite_code)
|
bsw@388
|
623 else
|
bsw@388
|
624 subject = config.mail_subject_prefix .. _"Invitation to LiquidFeedback"
|
bsw@388
|
625 content = slot.use_temporary(function()
|
bsw@388
|
626 slot.put(_"Hello\n\n")
|
bsw@388
|
627 slot.put(_"You are invited to LiquidFeedback. To register please click the following link:\n\n")
|
bsw/jbe@1309
|
628 slot.put(url .. "\n\n")
|
bsw@388
|
629 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw/jbe@1309
|
630 slot.put(baseurl .. "\n\n")
|
bsw@388
|
631 slot.put(_"On that page please enter the invite key:\n\n")
|
bsw@388
|
632 slot.put(self.invite_code .. "\n\n")
|
bsw@388
|
633 end)
|
bsw@388
|
634 end
|
bsw@388
|
635
|
bsw@286
|
636 local success = net.send_mail{
|
bsw@286
|
637 envelope_from = config.mail_envelope_from,
|
bsw@286
|
638 from = config.mail_from,
|
bsw@286
|
639 reply_to = config.mail_reply_to,
|
bsw@286
|
640 to = self.notify_email_unconfirmed or self.notify_email,
|
bsw@388
|
641 subject = subject,
|
bsw@286
|
642 content_type = "text/plain; charset=UTF-8",
|
bsw@286
|
643 content = content
|
bsw@286
|
644 }
|
bsw@286
|
645 return success
|
bsw/jbe@0
|
646 end
|
bsw@2
|
647
|
bsw/jbe@6
|
648 function Member.object:set_notify_email(notify_email)
|
bsw@224
|
649 trace.disable()
|
bsw/jbe@6
|
650 local expiry = db:query("SELECT now() + '7 days'::interval as expiry", "object").expiry
|
bsw/jbe@6
|
651 self.notify_email_unconfirmed = notify_email
|
jbe@1232
|
652 self.notify_email_secret = secret_token()
|
bsw/jbe@6
|
653 self.notify_email_secret_expiry = expiry
|
bsw/jbe@6
|
654 local content = slot.use_temporary(function()
|
bsw/jbe@6
|
655 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw/jbe@6
|
656 slot.put(_"Please confirm your email address by clicking the following link:\n\n")
|
jbe@326
|
657 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html?secret=" .. self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
658 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
jbe@326
|
659 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html\n\n")
|
bsw/jbe@6
|
660 slot.put(_"On that page please enter the confirmation code:\n\n")
|
bsw/jbe@6
|
661 slot.put(self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
662 end)
|
bsw/jbe@6
|
663 local success = net.send_mail{
|
bsw/jbe@6
|
664 envelope_from = config.mail_envelope_from,
|
bsw/jbe@6
|
665 from = config.mail_from,
|
bsw/jbe@6
|
666 reply_to = config.mail_reply_to,
|
bsw/jbe@6
|
667 to = self.notify_email_unconfirmed,
|
bsw/jbe@6
|
668 subject = config.mail_subject_prefix .. _"Email confirmation request",
|
bsw/jbe@6
|
669 content_type = "text/plain; charset=UTF-8",
|
bsw/jbe@6
|
670 content = content
|
bsw/jbe@6
|
671 }
|
bsw@75
|
672 if success then
|
bsw@75
|
673 local lock_expiry = db:query("SELECT now() + '1 hour'::interval AS lock_expiry", "object").lock_expiry
|
bsw@75
|
674 self.notify_email_lock_expiry = lock_expiry
|
bsw@75
|
675 end
|
bsw@75
|
676 self:save()
|
bsw/jbe@6
|
677 return success
|
bsw/jbe@6
|
678 end
|
bsw@11
|
679
|
bsw/jbe@19
|
680 function Member.object:get_setting(key)
|
bsw@79
|
681 return Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
682 end
|
bsw/jbe@19
|
683
|
bsw/jbe@19
|
684 function Member.object:get_setting_value(key)
|
bsw@79
|
685 local setting = Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
686 if setting then
|
bsw/jbe@19
|
687 return setting.value
|
bsw/jbe@19
|
688 end
|
bsw@11
|
689 end
|
bsw@11
|
690
|
bsw@11
|
691 function Member.object:set_setting(key, value)
|
bsw/jbe@19
|
692 local setting = self:get_setting(key)
|
bsw/jbe@19
|
693 if not setting then
|
bsw/jbe@19
|
694 setting = Setting:new()
|
bsw@79
|
695 setting.member_id = self.id
|
bsw/jbe@19
|
696 setting.key = key
|
bsw/jbe@19
|
697 end
|
bsw/jbe@19
|
698 setting.value = value
|
bsw/jbe@19
|
699 setting:save()
|
bsw@11
|
700 end
|
bsw@11
|
701
|
bsw@11
|
702 function Member.object:get_setting_maps_by_key(key)
|
bsw@11
|
703 return SettingMap:new_selector()
|
bsw@11
|
704 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
705 :add_where{ "key = ?", key }
|
bsw@11
|
706 :add_order_by("subkey")
|
bsw@11
|
707 :exec()
|
bsw@11
|
708 end
|
bsw@11
|
709
|
bsw@11
|
710 function Member.object:get_setting_map_by_key_and_subkey(key, subkey)
|
bsw@11
|
711 return SettingMap:new_selector()
|
bsw@11
|
712 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
713 :add_where{ "key = ?", key }
|
bsw@11
|
714 :add_where{ "subkey = ?", subkey }
|
bsw@11
|
715 :add_order_by("subkey")
|
bsw@11
|
716 :optional_object_mode()
|
bsw@11
|
717 :exec()
|
bsw@11
|
718 end
|
bsw@11
|
719
|
bsw@11
|
720 function Member.object:set_setting_map(key, subkey, value)
|
poelzi@144
|
721 setting_map = self:get_setting_map_by_key_and_subkey(key, subkey)
|
poelzi@144
|
722 if not setting_map then
|
poelzi@144
|
723 setting_map = SettingMap:new()
|
poelzi@144
|
724 setting_map.member_id = self.id
|
poelzi@144
|
725 setting_map.key = key
|
poelzi@144
|
726 setting_map.subkey = subkey
|
poelzi@144
|
727 end
|
poelzi@144
|
728 setting_map.value = value
|
poelzi@144
|
729 setting_map:save()
|
bsw@11
|
730 end
|
bsw@75
|
731
|
bsw@75
|
732 function Member.object_get:notify_email_locked()
|
bsw@75
|
733 return(
|
bsw@75
|
734 Member:new_selector()
|
bsw@75
|
735 :add_where{ "id = ?", app.session.member.id }
|
bsw@75
|
736 :add_where("notify_email_lock_expiry > now()")
|
bsw@75
|
737 :count() == 1
|
bsw@75
|
738 )
|
poelzi@134
|
739 end
|
poelzi@134
|
740
|
bsw@273
|
741 function Member.object_get:units_with_voting_right()
|
bsw@273
|
742 return(Unit:new_selector()
|
bsw@273
|
743 :join("privilege", nil, { "privilege.unit_id = unit.id AND privilege.member_id = ? AND privilege.voting_right", self.id })
|
bsw@273
|
744 :exec()
|
bsw@273
|
745 )
|
bsw@273
|
746 end
|
bsw@273
|
747
|
poelzi@134
|
748 function Member.object:ui_field_text(args)
|
poelzi@134
|
749 args = args or {}
|
bsw@813
|
750 if app.session:has_access("authors_pseudonymous") then
|
poelzi@134
|
751 -- ugly workaround for getting html into a replaced string and to the user
|
poelzi@134
|
752 ui.container{label = args.label, label_attr={class="ui_field_label"}, content = function()
|
poelzi@134
|
753 slot.put(string.format('<span><a href="%s">%s</a></span>',
|
poelzi@134
|
754 encode.url{
|
poelzi@134
|
755 module = "member",
|
poelzi@134
|
756 view = "show",
|
poelzi@134
|
757 id = self.id,
|
poelzi@134
|
758 },
|
poelzi@134
|
759 encode.html(self.name)))
|
poelzi@134
|
760 end
|
poelzi@134
|
761 }
|
poelzi@134
|
762 else
|
poelzi@134
|
763 ui.field.text{ label = args.label, value = _"[not displayed public]" }
|
poelzi@134
|
764 end
|
poelzi@134
|
765 end
|
bsw@281
|
766
|
bsw/jbe@1309
|
767 local function populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
768 if not self.__units_with_initiative_right_hash then
|
bsw/jbe@1309
|
769 local privileges = Privilege:new_selector()
|
bsw/jbe@1309
|
770 :add_where{ "member_id = ?", self.id }
|
bsw/jbe@1309
|
771 :add_where("initiative_right")
|
bsw/jbe@1309
|
772 :exec()
|
bsw/jbe@1309
|
773 self.__units_with_initiative_right_hash = {}
|
bsw/jbe@1309
|
774 for i, privilege in ipairs(privileges) do
|
bsw/jbe@1309
|
775 self.__units_with_initiative_right_hash[privilege.unit_id] = true
|
bsw/jbe@1309
|
776 end
|
bsw/jbe@1309
|
777 end
|
bsw/jbe@1309
|
778 end
|
bsw/jbe@1309
|
779
|
bsw/jbe@1309
|
780 function Member.object:has_initiative_right_for_unit_id(unit_id)
|
bsw/jbe@1309
|
781 populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
782 return self.__units_with_initiative_right_hash[unit_id] and true or false
|
bsw/jbe@1309
|
783 end
|
bsw/jbe@1309
|
784
|
bsw/jbe@1309
|
785 function Member.object_get:has_initiative_right()
|
bsw/jbe@1309
|
786 populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
787 for k, v in pairs(self.__units_with_initiative_right_hash) do
|
bsw/jbe@1309
|
788 return true
|
bsw/jbe@1309
|
789 end
|
bsw/jbe@1309
|
790 return false
|
bsw/jbe@1309
|
791 end
|
bsw/jbe@1309
|
792
|
bsw/jbe@1309
|
793 local function populate_units_with_voting_right_hash(self)
|
bsw@547
|
794 if not self.__units_with_voting_right_hash then
|
bsw@547
|
795 local privileges = Privilege:new_selector()
|
bsw@547
|
796 :add_where{ "member_id = ?", self.id }
|
bsw@547
|
797 :add_where("voting_right")
|
bsw@547
|
798 :exec()
|
bsw@547
|
799 self.__units_with_voting_right_hash = {}
|
bsw@551
|
800 for i, privilege in ipairs(privileges) do
|
bsw@551
|
801 self.__units_with_voting_right_hash[privilege.unit_id] = true
|
bsw@551
|
802 end
|
bsw@547
|
803 end
|
bsw/jbe@1309
|
804 end
|
bsw/jbe@1309
|
805
|
bsw/jbe@1309
|
806 function Member.object_get:has_voting_right()
|
bsw/jbe@1309
|
807 populate_units_with_voting_right_hash(self)
|
bsw/jbe@1309
|
808 for k, v in pairs(self.__units_with_voting_right_hash) do
|
bsw/jbe@1309
|
809 return true
|
bsw/jbe@1309
|
810 end
|
bsw/jbe@1309
|
811 return false
|
bsw/jbe@1309
|
812 end
|
bsw/jbe@1309
|
813
|
bsw/jbe@1309
|
814 function Member.object:has_voting_right_for_unit_id(unit_id)
|
bsw/jbe@1309
|
815 populate_units_with_voting_right_hash(self)
|
bsw@547
|
816 return self.__units_with_voting_right_hash[unit_id] and true or false
|
jbe@326
|
817 end
|
bsw@525
|
818
|
bsw@894
|
819 function Member.object:has_polling_right_for_unit_id(unit_id)
|
bsw@894
|
820 if not self.__units_with_polling_right_hash then
|
bsw@894
|
821 local privileges = Privilege:new_selector()
|
bsw@894
|
822 :add_where{ "member_id = ?", self.id }
|
bsw@894
|
823 :add_where("polling_right")
|
bsw@894
|
824 :exec()
|
bsw@894
|
825 self.__units_with_polling_right_hash = {}
|
bsw@894
|
826 for i, privilege in ipairs(privileges) do
|
bsw@894
|
827 self.__units_with_polling_right_hash[privilege.unit_id] = true
|
bsw@894
|
828 end
|
bsw@894
|
829 end
|
bsw@894
|
830 return self.__units_with_polling_right_hash[unit_id] and true or false
|
bsw@894
|
831 end
|
bsw@894
|
832
|
bsw@525
|
833 function Member.object:get_delegatee_member(unit_id, area_id, issue_id)
|
bsw@525
|
834 local selector = Member:new_selector()
|
bsw@525
|
835 if unit_id then
|
bsw@525
|
836 selector:join("delegation", nil, { "delegation.trustee_id = member.id AND delegation.scope = 'unit' AND delegation.unit_id = ? AND delegation.truster_id = ?", unit_id, self.id })
|
bsw@525
|
837 end
|
bsw@525
|
838 selector:optional_object_mode()
|
bsw@525
|
839 return selector:exec()
|
bsw@533
|
840 end
|
bsw@929
|
841
|
bsw@1504
|
842 function Member.object:has_role(role)
|
bsw@1508
|
843 self:load("units")
|
bsw@1508
|
844 for i, unit in ipairs(self.units) do
|
bsw@1504
|
845 if unit.attr.role == role then
|
bsw@1504
|
846 return true
|
bsw@1504
|
847 end
|
bsw@1504
|
848 end
|
bsw@1504
|
849 return false
|
bsw@1504
|
850 end
|
bsw@1504
|
851
|
bsw@1088
|
852 function Member.object:delete()
|
bsw@1088
|
853 db:query{ "SELECT delete_member(?)", self.id }
|
bsw@1088
|
854 end
|
bsw/jbe@1309
|
855
|
bsw/jbe@1309
|
856 function Member.object_get:display_name()
|
bsw/jbe@1309
|
857 if self.identification then
|
bsw/jbe@1309
|
858 return self.identification
|
bsw/jbe@1309
|
859 elseif self.name then
|
bsw/jbe@1309
|
860 return self.name
|
bsw/jbe@1309
|
861 else
|
bsw/jbe@1309
|
862 return "Member #" .. self.id
|
bsw/jbe@1309
|
863 end
|
bsw/jbe@1309
|
864 end
|