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:optional_object_mode()
|
bsw@1071
|
417 return selector
|
bsw@1071
|
418 end
|
bsw@1071
|
419
|
bsw@1071
|
420 local function do_local_login()
|
bsw@1071
|
421 local selector = prepare_login_selector()
|
bsw@1071
|
422 selector:add_where{'"login" = ?', login }
|
bsw@1071
|
423 local member = selector:exec()
|
bsw@1071
|
424 if member and member:check_password(password) then
|
bsw@1071
|
425 return member
|
bsw@1071
|
426 else
|
bsw@1071
|
427 return nil
|
bsw@1071
|
428 end
|
bsw/jbe@0
|
429 end
|
bsw@1071
|
430
|
bsw@1071
|
431 if config.ldap.member then
|
bsw@1071
|
432
|
bsw@1071
|
433 -- Let's check the users credentials against the LDAP
|
bsw@1071
|
434 local ldap_entry, ldap_err = ldap.check_credentials(login, password)
|
bsw@1071
|
435
|
bsw@1071
|
436 -- Is the user already registered as member?
|
bsw@1071
|
437 local uid
|
bsw@1071
|
438 local selector = prepare_login_selector()
|
bsw@1071
|
439
|
bsw@1071
|
440 -- Get login name from LDAP entry
|
bsw@1071
|
441 if ldap_entry then
|
bsw@1071
|
442 uid = config.ldap.member.uid_map(ldap_entry)
|
bsw@1074
|
443 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", uid }
|
bsw@1071
|
444
|
bsw@1071
|
445 -- or build it from the login
|
bsw@1071
|
446 else
|
bsw@1071
|
447 login = config.ldap.member.login_normalizer(login)
|
bsw@1074
|
448 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", login }
|
bsw@1071
|
449 end
|
bsw@1071
|
450
|
bsw@1071
|
451 local member = selector:exec()
|
bsw@1071
|
452 -- The member is already registered
|
bsw@1071
|
453 if member then
|
bsw@1071
|
454
|
bsw@1071
|
455 -- The credentials entered by the user are invalid
|
bsw@1071
|
456 if ldap_err == "invalid_credentials" then
|
bsw@1071
|
457
|
bsw@1071
|
458 -- Check if the user tried a cached password (which is invalid now)
|
bsw@1071
|
459 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
460 member.password = nil
|
bsw@1071
|
461 member:save()
|
bsw@1071
|
462 end
|
bsw@1071
|
463
|
bsw@1071
|
464 -- Try a regular login
|
bsw@1071
|
465 return do_local_login()
|
bsw@1071
|
466
|
bsw@1071
|
467 end
|
bsw@1071
|
468
|
bsw@1071
|
469 -- The credentials were accepted by the LDAP server and no error occured
|
bsw@1071
|
470 if ldap_entry and not ldap_err then
|
bsw@1071
|
471
|
bsw@1071
|
472 -- Cache the password (if feature enabled)
|
bsw@1071
|
473 if config.ldap.member.cache_passwords and not member:check_password(password) then
|
bsw@1071
|
474 member:set_password(password)
|
bsw@1071
|
475 end
|
bsw@1071
|
476
|
bsw@1071
|
477 -- update the member attributes and privileges from LDAP
|
bsw@1642
|
478 local ldap_conn, ldap_entry, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
479 if not err then
|
bsw@1642
|
480 ldap.update_member_allowed(member, ldap_entry)
|
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@1642
|
485 if member.locked then
|
bsw@1642
|
486 return nil, "member_locked"
|
bsw@1642
|
487 end
|
bsw@1071
|
488 local succes, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
489 if err then
|
bsw@1071
|
490 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
491 end
|
bsw@1071
|
492 return member
|
bsw@1071
|
493 end
|
bsw@1071
|
494
|
bsw@1071
|
495 end
|
bsw@1071
|
496
|
bsw@1071
|
497 -- Some kind of LDAP error happened, if cached password are enabled,
|
bsw@1071
|
498 -- check user credentials against the cache
|
bsw@1071
|
499 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
500
|
bsw@1071
|
501 -- return the successfully logged in member
|
bsw@1071
|
502 return member
|
bsw@1071
|
503
|
bsw@1071
|
504 end
|
bsw@1071
|
505
|
bsw@1071
|
506 -- The member is not registered
|
bsw@1071
|
507 elseif config.ldap.member.registration and ldap_entry and not ldap_err then
|
bsw@1071
|
508 -- Automatic registration ("auto")
|
bsw@1071
|
509 if config.ldap.member.registration == "auto" then
|
bsw@1071
|
510 member = Member:new()
|
bsw@1071
|
511 member.authority = "ldap"
|
bsw@1071
|
512 local ldap_login
|
bsw@1071
|
513 if config.ldap.member.cache_passwords then
|
bsw@1071
|
514 if config.ldap.member.login_normalizer then
|
bsw@1071
|
515 ldap_login = config.ldap.member.login_normalizer(login)
|
bsw@1071
|
516 else
|
bsw@1071
|
517 ldap_login = login
|
bsw@1071
|
518 end
|
bsw@1071
|
519 end
|
bsw@1071
|
520 -- TODO change this when SQL layers supports hstore
|
bsw@1074
|
521 member.authority_uid = uid
|
bsw@1074
|
522 member.authority_login = ldap_login
|
bsw@1071
|
523 member.activated = "now"
|
bsw@1071
|
524 member.last_activity = "now"
|
bsw@1071
|
525 if config.ldap.member.cache_passwords then
|
bsw@1071
|
526 member:set_password(password)
|
bsw@1071
|
527 end
|
bsw@1642
|
528 local ldap_conn, ldap_entry, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
529 if not err then
|
bsw@1642
|
530 ldap.update_member_allowed(member, ldap_entry)
|
bsw@1642
|
531 if member.locked then
|
bsw@1642
|
532 return nil, "member_not_allowed"
|
bsw@1642
|
533 end
|
bsw@1071
|
534 local err = member:try_save()
|
bsw@1071
|
535 if err then
|
bsw@1071
|
536 return nil, "member_save_error", err
|
bsw@1071
|
537 end
|
bsw@1071
|
538 local success, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
539 if err then
|
bsw@1071
|
540 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
541 end
|
bsw@1071
|
542 return member
|
bsw@1071
|
543 end
|
bsw@1071
|
544
|
bsw@1071
|
545 -- No automatic registration
|
bsw@1071
|
546 else
|
bsw@1071
|
547 return nil, "ldap_credentials_valid_but_no_member", uid
|
bsw@1071
|
548 end
|
bsw@1071
|
549 end
|
bsw@1071
|
550
|
bsw@1071
|
551 end
|
bsw@1071
|
552
|
bsw@1071
|
553 return do_local_login()
|
bsw@1071
|
554
|
bsw/jbe@0
|
555 end
|
bsw/jbe@0
|
556
|
bsw/jbe@1309
|
557 function Member:by_ids(ids)
|
bsw/jbe@1309
|
558 local selector = self:new_selector()
|
bsw/jbe@1309
|
559 selector:add_where{'"id" IN ($)', { ids } }
|
bsw/jbe@1309
|
560 return selector:exec()
|
bsw/jbe@1309
|
561 end
|
bsw/jbe@1309
|
562
|
bsw/jbe@5
|
563 function Member:by_login(login)
|
bsw/jbe@5
|
564 local selector = self:new_selector()
|
bsw/jbe@5
|
565 selector:add_where{'"login" = ?', login }
|
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/jbe@5
|
570 function Member:by_name(name)
|
bsw/jbe@5
|
571 local selector = self:new_selector()
|
bsw/jbe@5
|
572 selector:add_where{'"name" = ?', name }
|
bsw/jbe@5
|
573 selector:optional_object_mode()
|
bsw/jbe@5
|
574 return selector:exec()
|
bsw/jbe@5
|
575 end
|
bsw/jbe@5
|
576
|
bsw@2
|
577 function Member:get_search_selector(search_string)
|
bsw/jbe@0
|
578 return self:new_selector()
|
bsw@2
|
579 :add_field( {'"highlight"("member"."name", ?)', search_string }, "name_highlighted")
|
bsw@1492
|
580 :add_where{ 'to_tsvector("member") @@ "plainto_tsquery"(?)', search_string }
|
bsw@362
|
581 :add_where("activated NOTNULL AND active")
|
bsw/jbe@0
|
582 end
|
bsw@2
|
583
|
bsw@1231
|
584 function Member.object:send_password_reset_mail()
|
bsw@1231
|
585 trace.disable()
|
bsw@1231
|
586 if not self.notify_email then
|
bsw@1231
|
587 return false
|
bsw@1231
|
588 end
|
jbe@1232
|
589 self.password_reset_secret = secret_token()
|
bsw@1231
|
590 local expiry = db:query("SELECT now() + '1 days'::interval as expiry", "object").expiry
|
bsw@1231
|
591 self.password_reset_secret_expiry = expiry
|
bsw@1231
|
592 self:save()
|
bsw@1231
|
593 local content = slot.use_temporary(function()
|
bsw@1231
|
594 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw@1231
|
595 slot.put(_"to reset your password please click on the following link:\n\n")
|
bsw@1231
|
596 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html?secret=" .. self.password_reset_secret .. "\n\n")
|
bsw@1231
|
597 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw@1231
|
598 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html\n\n")
|
bsw@1231
|
599 slot.put(_"On that page please enter the reset code:\n\n")
|
bsw@1231
|
600 slot.put(self.password_reset_secret .. "\n\n")
|
bsw@1231
|
601 end)
|
bsw@1231
|
602 local success = net.send_mail{
|
bsw@1231
|
603 envelope_from = config.mail_envelope_from,
|
bsw@1231
|
604 from = config.mail_from,
|
bsw@1231
|
605 reply_to = config.mail_reply_to,
|
bsw@1231
|
606 to = self.notify_email,
|
bsw@1231
|
607 subject = config.mail_subject_prefix .. _"Password reset request",
|
bsw@1231
|
608 content_type = "text/plain; charset=UTF-8",
|
bsw@1231
|
609 content = content
|
bsw@1231
|
610 }
|
bsw@1231
|
611 return success
|
bsw@1231
|
612 end
|
bsw@1231
|
613
|
bsw@388
|
614 function Member.object:send_invitation(template_file, subject)
|
bsw@286
|
615 trace.disable()
|
jbe@1232
|
616 self.invite_code = secret_token()
|
bsw@388
|
617 self:save()
|
bsw@388
|
618
|
bsw@388
|
619 local subject = subject
|
bsw@388
|
620 local content
|
bsw/jbe@1309
|
621 local baseurl = request.get_absolute_baseurl() .. "index/register.html"
|
bsw/jbe@1309
|
622 local url = baseurl .. "?skip=1&code=" .. self.invite_code
|
bsw@388
|
623 if template_file then
|
bsw@388
|
624 local fh = io.open(template_file, "r")
|
bsw@388
|
625 content = fh:read("*a")
|
bsw/jbe@1309
|
626 content = content:gsub("#{url}", url):gsub("#{baseurl}", baseurl):gsub("#{code}", self.invite_code)
|
bsw/jbe@1309
|
627 elseif config.invitation_mail then
|
bsw/jbe@1309
|
628 subject = config.invitation_mail.subject
|
bsw/jbe@1309
|
629 content = config.invitation_mail.content:gsub("#{url}", url):gsub("#{baseurl}", baseurl):gsub("#{code}", self.invite_code)
|
bsw@388
|
630 else
|
bsw@388
|
631 subject = config.mail_subject_prefix .. _"Invitation to LiquidFeedback"
|
bsw@388
|
632 content = slot.use_temporary(function()
|
bsw@388
|
633 slot.put(_"Hello\n\n")
|
bsw@388
|
634 slot.put(_"You are invited to LiquidFeedback. To register please click the following link:\n\n")
|
bsw/jbe@1309
|
635 slot.put(url .. "\n\n")
|
bsw@388
|
636 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw/jbe@1309
|
637 slot.put(baseurl .. "\n\n")
|
bsw@388
|
638 slot.put(_"On that page please enter the invite key:\n\n")
|
bsw@388
|
639 slot.put(self.invite_code .. "\n\n")
|
bsw@388
|
640 end)
|
bsw@388
|
641 end
|
bsw@388
|
642
|
bsw@286
|
643 local success = net.send_mail{
|
bsw@286
|
644 envelope_from = config.mail_envelope_from,
|
bsw@286
|
645 from = config.mail_from,
|
bsw@286
|
646 reply_to = config.mail_reply_to,
|
bsw@286
|
647 to = self.notify_email_unconfirmed or self.notify_email,
|
bsw@388
|
648 subject = subject,
|
bsw@286
|
649 content_type = "text/plain; charset=UTF-8",
|
bsw@286
|
650 content = content
|
bsw@286
|
651 }
|
bsw@286
|
652 return success
|
bsw/jbe@0
|
653 end
|
bsw@2
|
654
|
bsw/jbe@6
|
655 function Member.object:set_notify_email(notify_email)
|
bsw@224
|
656 trace.disable()
|
bsw/jbe@6
|
657 local expiry = db:query("SELECT now() + '7 days'::interval as expiry", "object").expiry
|
bsw/jbe@6
|
658 self.notify_email_unconfirmed = notify_email
|
jbe@1232
|
659 self.notify_email_secret = secret_token()
|
bsw/jbe@6
|
660 self.notify_email_secret_expiry = expiry
|
bsw/jbe@6
|
661 local content = slot.use_temporary(function()
|
bsw/jbe@6
|
662 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw/jbe@6
|
663 slot.put(_"Please confirm your email address by clicking the following link:\n\n")
|
jbe@326
|
664 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html?secret=" .. self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
665 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
jbe@326
|
666 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html\n\n")
|
bsw/jbe@6
|
667 slot.put(_"On that page please enter the confirmation code:\n\n")
|
bsw/jbe@6
|
668 slot.put(self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
669 end)
|
bsw/jbe@6
|
670 local success = net.send_mail{
|
bsw/jbe@6
|
671 envelope_from = config.mail_envelope_from,
|
bsw/jbe@6
|
672 from = config.mail_from,
|
bsw/jbe@6
|
673 reply_to = config.mail_reply_to,
|
bsw/jbe@6
|
674 to = self.notify_email_unconfirmed,
|
bsw/jbe@6
|
675 subject = config.mail_subject_prefix .. _"Email confirmation request",
|
bsw/jbe@6
|
676 content_type = "text/plain; charset=UTF-8",
|
bsw/jbe@6
|
677 content = content
|
bsw/jbe@6
|
678 }
|
bsw@75
|
679 if success then
|
bsw@75
|
680 local lock_expiry = db:query("SELECT now() + '1 hour'::interval AS lock_expiry", "object").lock_expiry
|
bsw@75
|
681 self.notify_email_lock_expiry = lock_expiry
|
bsw@75
|
682 end
|
bsw@75
|
683 self:save()
|
bsw/jbe@6
|
684 return success
|
bsw/jbe@6
|
685 end
|
bsw@11
|
686
|
bsw/jbe@19
|
687 function Member.object:get_setting(key)
|
bsw@79
|
688 return Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
689 end
|
bsw/jbe@19
|
690
|
bsw/jbe@19
|
691 function Member.object:get_setting_value(key)
|
bsw@79
|
692 local setting = Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
693 if setting then
|
bsw/jbe@19
|
694 return setting.value
|
bsw/jbe@19
|
695 end
|
bsw@11
|
696 end
|
bsw@11
|
697
|
bsw@11
|
698 function Member.object:set_setting(key, value)
|
bsw/jbe@19
|
699 local setting = self:get_setting(key)
|
bsw/jbe@19
|
700 if not setting then
|
bsw/jbe@19
|
701 setting = Setting:new()
|
bsw@79
|
702 setting.member_id = self.id
|
bsw/jbe@19
|
703 setting.key = key
|
bsw/jbe@19
|
704 end
|
bsw/jbe@19
|
705 setting.value = value
|
bsw/jbe@19
|
706 setting:save()
|
bsw@11
|
707 end
|
bsw@11
|
708
|
bsw@11
|
709 function Member.object:get_setting_maps_by_key(key)
|
bsw@11
|
710 return SettingMap:new_selector()
|
bsw@11
|
711 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
712 :add_where{ "key = ?", key }
|
bsw@11
|
713 :add_order_by("subkey")
|
bsw@11
|
714 :exec()
|
bsw@11
|
715 end
|
bsw@11
|
716
|
bsw@11
|
717 function Member.object:get_setting_map_by_key_and_subkey(key, subkey)
|
bsw@11
|
718 return SettingMap:new_selector()
|
bsw@11
|
719 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
720 :add_where{ "key = ?", key }
|
bsw@11
|
721 :add_where{ "subkey = ?", subkey }
|
bsw@11
|
722 :add_order_by("subkey")
|
bsw@11
|
723 :optional_object_mode()
|
bsw@11
|
724 :exec()
|
bsw@11
|
725 end
|
bsw@11
|
726
|
bsw@11
|
727 function Member.object:set_setting_map(key, subkey, value)
|
poelzi@144
|
728 setting_map = self:get_setting_map_by_key_and_subkey(key, subkey)
|
poelzi@144
|
729 if not setting_map then
|
poelzi@144
|
730 setting_map = SettingMap:new()
|
poelzi@144
|
731 setting_map.member_id = self.id
|
poelzi@144
|
732 setting_map.key = key
|
poelzi@144
|
733 setting_map.subkey = subkey
|
poelzi@144
|
734 end
|
poelzi@144
|
735 setting_map.value = value
|
poelzi@144
|
736 setting_map:save()
|
bsw@11
|
737 end
|
bsw@75
|
738
|
bsw@75
|
739 function Member.object_get:notify_email_locked()
|
bsw@75
|
740 return(
|
bsw@75
|
741 Member:new_selector()
|
bsw@75
|
742 :add_where{ "id = ?", app.session.member.id }
|
bsw@75
|
743 :add_where("notify_email_lock_expiry > now()")
|
bsw@75
|
744 :count() == 1
|
bsw@75
|
745 )
|
poelzi@134
|
746 end
|
poelzi@134
|
747
|
bsw@273
|
748 function Member.object_get:units_with_voting_right()
|
bsw@273
|
749 return(Unit:new_selector()
|
bsw@273
|
750 :join("privilege", nil, { "privilege.unit_id = unit.id AND privilege.member_id = ? AND privilege.voting_right", self.id })
|
bsw@273
|
751 :exec()
|
bsw@273
|
752 )
|
bsw@273
|
753 end
|
bsw@273
|
754
|
poelzi@134
|
755 function Member.object:ui_field_text(args)
|
poelzi@134
|
756 args = args or {}
|
bsw@813
|
757 if app.session:has_access("authors_pseudonymous") then
|
poelzi@134
|
758 -- ugly workaround for getting html into a replaced string and to the user
|
poelzi@134
|
759 ui.container{label = args.label, label_attr={class="ui_field_label"}, content = function()
|
poelzi@134
|
760 slot.put(string.format('<span><a href="%s">%s</a></span>',
|
poelzi@134
|
761 encode.url{
|
poelzi@134
|
762 module = "member",
|
poelzi@134
|
763 view = "show",
|
poelzi@134
|
764 id = self.id,
|
poelzi@134
|
765 },
|
poelzi@134
|
766 encode.html(self.name)))
|
poelzi@134
|
767 end
|
poelzi@134
|
768 }
|
poelzi@134
|
769 else
|
poelzi@134
|
770 ui.field.text{ label = args.label, value = _"[not displayed public]" }
|
poelzi@134
|
771 end
|
poelzi@134
|
772 end
|
bsw@281
|
773
|
bsw/jbe@1309
|
774 local function populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
775 if not self.__units_with_initiative_right_hash then
|
bsw/jbe@1309
|
776 local privileges = Privilege:new_selector()
|
bsw/jbe@1309
|
777 :add_where{ "member_id = ?", self.id }
|
bsw/jbe@1309
|
778 :add_where("initiative_right")
|
bsw/jbe@1309
|
779 :exec()
|
bsw/jbe@1309
|
780 self.__units_with_initiative_right_hash = {}
|
bsw/jbe@1309
|
781 for i, privilege in ipairs(privileges) do
|
bsw/jbe@1309
|
782 self.__units_with_initiative_right_hash[privilege.unit_id] = true
|
bsw/jbe@1309
|
783 end
|
bsw/jbe@1309
|
784 end
|
bsw/jbe@1309
|
785 end
|
bsw/jbe@1309
|
786
|
bsw/jbe@1309
|
787 function Member.object:has_initiative_right_for_unit_id(unit_id)
|
bsw/jbe@1309
|
788 populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
789 return self.__units_with_initiative_right_hash[unit_id] and true or false
|
bsw/jbe@1309
|
790 end
|
bsw/jbe@1309
|
791
|
bsw/jbe@1309
|
792 function Member.object_get:has_initiative_right()
|
bsw/jbe@1309
|
793 populate_units_with_initiative_right_hash(self)
|
bsw/jbe@1309
|
794 for k, v in pairs(self.__units_with_initiative_right_hash) do
|
bsw/jbe@1309
|
795 return true
|
bsw/jbe@1309
|
796 end
|
bsw/jbe@1309
|
797 return false
|
bsw/jbe@1309
|
798 end
|
bsw/jbe@1309
|
799
|
bsw/jbe@1309
|
800 local function populate_units_with_voting_right_hash(self)
|
bsw@547
|
801 if not self.__units_with_voting_right_hash then
|
bsw@547
|
802 local privileges = Privilege:new_selector()
|
bsw@547
|
803 :add_where{ "member_id = ?", self.id }
|
bsw@547
|
804 :add_where("voting_right")
|
bsw@547
|
805 :exec()
|
bsw@547
|
806 self.__units_with_voting_right_hash = {}
|
bsw@551
|
807 for i, privilege in ipairs(privileges) do
|
bsw@551
|
808 self.__units_with_voting_right_hash[privilege.unit_id] = true
|
bsw@551
|
809 end
|
bsw@547
|
810 end
|
bsw/jbe@1309
|
811 end
|
bsw/jbe@1309
|
812
|
bsw/jbe@1309
|
813 function Member.object_get:has_voting_right()
|
bsw/jbe@1309
|
814 populate_units_with_voting_right_hash(self)
|
bsw/jbe@1309
|
815 for k, v in pairs(self.__units_with_voting_right_hash) do
|
bsw/jbe@1309
|
816 return true
|
bsw/jbe@1309
|
817 end
|
bsw/jbe@1309
|
818 return false
|
bsw/jbe@1309
|
819 end
|
bsw/jbe@1309
|
820
|
bsw/jbe@1309
|
821 function Member.object:has_voting_right_for_unit_id(unit_id)
|
bsw/jbe@1309
|
822 populate_units_with_voting_right_hash(self)
|
bsw@547
|
823 return self.__units_with_voting_right_hash[unit_id] and true or false
|
jbe@326
|
824 end
|
bsw@525
|
825
|
bsw@894
|
826 function Member.object:has_polling_right_for_unit_id(unit_id)
|
bsw@894
|
827 if not self.__units_with_polling_right_hash then
|
bsw@894
|
828 local privileges = Privilege:new_selector()
|
bsw@894
|
829 :add_where{ "member_id = ?", self.id }
|
bsw@894
|
830 :add_where("polling_right")
|
bsw@894
|
831 :exec()
|
bsw@894
|
832 self.__units_with_polling_right_hash = {}
|
bsw@894
|
833 for i, privilege in ipairs(privileges) do
|
bsw@894
|
834 self.__units_with_polling_right_hash[privilege.unit_id] = true
|
bsw@894
|
835 end
|
bsw@894
|
836 end
|
bsw@894
|
837 return self.__units_with_polling_right_hash[unit_id] and true or false
|
bsw@894
|
838 end
|
bsw@894
|
839
|
bsw@1696
|
840 function Member.object:get_single_unit_id()
|
bsw@1696
|
841 populate_units_with_voting_right_hash(self)
|
bsw@1696
|
842 local single_unit_id
|
bsw@1696
|
843 local count = 0
|
bsw@1696
|
844 for unit_id in pairs(self.__units_with_voting_right_hash) do
|
bsw@1696
|
845 single_unit_id = unit_id
|
bsw@1696
|
846 count = count + 1
|
bsw@1696
|
847 end
|
bsw@1696
|
848 if count == 1 then
|
bsw@1696
|
849 return single_unit_id
|
bsw@1696
|
850 end
|
bsw@1696
|
851 end
|
bsw@1696
|
852
|
bsw@525
|
853 function Member.object:get_delegatee_member(unit_id, area_id, issue_id)
|
bsw@525
|
854 local selector = Member:new_selector()
|
bsw@525
|
855 if unit_id then
|
bsw@525
|
856 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
|
857 end
|
bsw@525
|
858 selector:optional_object_mode()
|
bsw@525
|
859 return selector:exec()
|
bsw@533
|
860 end
|
bsw@929
|
861
|
bsw@1504
|
862 function Member.object:has_role(role)
|
bsw@1508
|
863 self:load("units")
|
bsw@1508
|
864 for i, unit in ipairs(self.units) do
|
bsw@1504
|
865 if unit.attr.role == role then
|
bsw@1504
|
866 return true
|
bsw@1504
|
867 end
|
bsw@1504
|
868 end
|
bsw@1504
|
869 return false
|
bsw@1504
|
870 end
|
bsw@1504
|
871
|
bsw@1088
|
872 function Member.object:delete()
|
bsw@1088
|
873 db:query{ "SELECT delete_member(?)", self.id }
|
bsw@1088
|
874 end
|
bsw/jbe@1309
|
875
|
bsw/jbe@1309
|
876 function Member.object_get:display_name()
|
bsw/jbe@1309
|
877 if self.identification then
|
bsw/jbe@1309
|
878 return self.identification
|
bsw/jbe@1309
|
879 elseif self.name then
|
bsw/jbe@1309
|
880 return self.name
|
bsw/jbe@1309
|
881 else
|
bsw/jbe@1309
|
882 return "Member #" .. self.id
|
bsw/jbe@1309
|
883 end
|
bsw/jbe@1309
|
884 end
|