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@0
|
169 mode = 'mm',
|
bsw/jbe@0
|
170 to = "Member",
|
bsw/jbe@0
|
171 this_key = 'id',
|
bsw/jbe@0
|
172 that_key = 'id',
|
bsw/jbe@0
|
173 connected_by_table = 'contact',
|
bsw/jbe@0
|
174 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
175 connected_by_that_key = 'other_member_id',
|
bsw/jbe@0
|
176 ref = 'saved_members',
|
bsw/jbe@0
|
177 }
|
bsw/jbe@0
|
178
|
bsw/jbe@0
|
179 Member:add_reference{
|
bsw/jbe@0
|
180 mode = 'mm',
|
bsw/jbe@0
|
181 to = "Member",
|
bsw/jbe@0
|
182 this_key = 'id',
|
bsw/jbe@0
|
183 that_key = 'id',
|
bsw/jbe@0
|
184 connected_by_table = 'contact',
|
bsw/jbe@0
|
185 connected_by_this_key = 'other_member_id',
|
bsw/jbe@0
|
186 connected_by_that_key = 'member_id',
|
bsw/jbe@0
|
187 ref = 'saved_by_members',
|
bsw/jbe@0
|
188 }
|
bsw/jbe@0
|
189
|
bsw/jbe@0
|
190 Member:add_reference{
|
bsw/jbe@0
|
191 mode = 'mm',
|
bsw@281
|
192 to = "Unit",
|
bsw@281
|
193 this_key = 'id',
|
bsw@281
|
194 that_key = 'id',
|
bsw@281
|
195 connected_by_table = 'privilege',
|
bsw@281
|
196 connected_by_this_key = 'member_id',
|
bsw@281
|
197 connected_by_that_key = 'unit_id',
|
bsw@281
|
198 ref = 'units'
|
bsw@281
|
199 }
|
bsw@281
|
200
|
bsw@281
|
201 Member:add_reference{
|
bsw@281
|
202 mode = 'mm',
|
bsw/jbe@0
|
203 to = "Area",
|
bsw/jbe@0
|
204 this_key = 'id',
|
bsw/jbe@0
|
205 that_key = 'id',
|
bsw/jbe@0
|
206 connected_by_table = 'membership',
|
bsw/jbe@0
|
207 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
208 connected_by_that_key = 'area_id',
|
bsw/jbe@0
|
209 ref = 'areas'
|
bsw/jbe@0
|
210 }
|
bsw/jbe@0
|
211
|
bsw/jbe@0
|
212 Member:add_reference{
|
bsw/jbe@0
|
213 mode = 'mm',
|
bsw/jbe@0
|
214 to = "Issue",
|
bsw/jbe@0
|
215 this_key = 'id',
|
bsw/jbe@0
|
216 that_key = 'id',
|
bsw/jbe@0
|
217 connected_by_table = 'interest',
|
bsw/jbe@0
|
218 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
219 connected_by_that_key = 'issue_id',
|
bsw/jbe@0
|
220 ref = 'issues'
|
bsw/jbe@0
|
221 }
|
bsw/jbe@0
|
222
|
bsw/jbe@0
|
223 Member:add_reference{
|
bsw/jbe@0
|
224 mode = 'mm',
|
bsw/jbe@0
|
225 to = "Initiative",
|
bsw/jbe@0
|
226 this_key = 'id',
|
bsw/jbe@0
|
227 that_key = 'id',
|
bsw/jbe@0
|
228 connected_by_table = 'initiator',
|
bsw/jbe@0
|
229 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
230 connected_by_that_key = 'initiative_id',
|
bsw/jbe@0
|
231 ref = 'initiated_initiatives'
|
bsw/jbe@0
|
232 }
|
bsw/jbe@0
|
233
|
bsw/jbe@0
|
234 Member:add_reference{
|
bsw/jbe@0
|
235 mode = 'mm',
|
bsw/jbe@0
|
236 to = "Initiative",
|
bsw/jbe@0
|
237 this_key = 'id',
|
bsw/jbe@0
|
238 that_key = 'id',
|
bsw/jbe@0
|
239 connected_by_table = 'supporter',
|
bsw/jbe@0
|
240 connected_by_this_key = 'member_id',
|
bsw/jbe@0
|
241 connected_by_that_key = 'initiative_id',
|
bsw/jbe@0
|
242 ref = 'supported_initiatives'
|
bsw/jbe@0
|
243 }
|
bsw/jbe@0
|
244
|
bsw@279
|
245 model.has_rendered_content(Member, RenderedMemberStatement, "statement")
|
bsw@279
|
246
|
bsw@193
|
247 function Member:build_selector(args)
|
bsw@193
|
248 local selector = self:new_selector()
|
bsw@193
|
249 if args.active ~= nil then
|
bsw@193
|
250 selector:add_where{ "member.active = ?", args.active }
|
bsw@193
|
251 end
|
bsw@581
|
252 if args.locked ~= nil then
|
bsw@581
|
253 selector:add_where{ "member.locked = ?", args.locked }
|
bsw@581
|
254 end
|
bsw@199
|
255 if args.is_contact_of_member_id then
|
bsw@199
|
256 selector:join("contact", "__model_member__contact", "member.id = __model_member__contact.other_member_id")
|
bsw@199
|
257 selector:add_where{ "__model_member__contact.member_id = ?", args.is_contact_of_member_id }
|
bsw@199
|
258 end
|
bsw@297
|
259 if args.voting_right_for_unit_id then
|
bsw@299
|
260 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
|
261 end
|
bsw@581
|
262 if args.admin_search then
|
bsw@581
|
263 local search_string = "%" .. args.admin_search .. "%"
|
bsw@581
|
264 selector:add_where{ "member.identification ILIKE ? OR member.name ILIKE ?", search_string, search_string }
|
bsw@581
|
265 end
|
bsw@193
|
266 if args.order then
|
bsw@193
|
267 if args.order == "id" then
|
bsw@193
|
268 selector:add_order_by("id")
|
bsw@581
|
269 elseif args.order == "identification" then
|
bsw@581
|
270 selector:add_order_by("identification")
|
bsw@193
|
271 elseif args.order == "name" then
|
bsw@193
|
272 selector:add_order_by("name")
|
bsw@193
|
273 else
|
bsw@193
|
274 error("invalid order")
|
bsw@193
|
275 end
|
bsw@193
|
276 end
|
bsw@193
|
277 return selector
|
bsw@193
|
278 end
|
bsw@193
|
279
|
bsw@929
|
280 function Member:lockForReference()
|
bsw@929
|
281 self.get_db_conn().query("LOCK TABLE " .. self:get_qualified_table() .. " IN ROW SHARE MODE")
|
bsw@929
|
282 end
|
bsw@929
|
283
|
bsw@1071
|
284
|
bsw@1071
|
285 function Member:get_all_by_authority(authority)
|
bsw@1071
|
286
|
bsw@1071
|
287 local members = Member:new_selector()
|
bsw@1071
|
288 :add_where{ "authority = ?", authority }
|
bsw@1074
|
289 :add_field("authority_uid")
|
bsw@1071
|
290 :exec()
|
bsw@1071
|
291
|
bsw@1071
|
292 return members
|
bsw@1071
|
293 end
|
bsw@1071
|
294
|
bsw/jbe@0
|
295 function Member.object:set_password(password)
|
bsw@865
|
296 trace.disable()
|
bsw@905
|
297
|
bsw@905
|
298 local hash_prefix
|
bsw@905
|
299 local salt_length
|
bsw@905
|
300
|
bsw@905
|
301 local function rounds()
|
bsw@905
|
302 return multirand.integer(
|
bsw@905
|
303 config.password_hash_min_rounds,
|
bsw@905
|
304 config.password_hash_max_rounds
|
bsw@905
|
305 )
|
bsw@905
|
306 end
|
bsw@905
|
307
|
bsw@905
|
308 if config.password_hash_algorithm == "crypt_md5" then
|
bsw@905
|
309 hash_prefix = "$1$"
|
bsw@905
|
310 salt_length = 8
|
bsw@905
|
311
|
bsw@905
|
312 elseif config.password_hash_algorithm == "crypt_sha256" then
|
bsw@905
|
313 hash_prefix = "$5$rounds=" .. rounds() .. "$"
|
bsw@905
|
314 salt_length = 16
|
bsw@905
|
315
|
bsw@905
|
316 elseif config.password_hash_algorithm == "crypt_sha512" then
|
bsw@905
|
317 hash_prefix = "$6$rounds=" .. rounds() .. "$"
|
bsw@905
|
318 salt_length = 16
|
bsw@905
|
319
|
bsw@905
|
320 else
|
bsw@905
|
321 error("Unknown hash algorithm selected in configuration")
|
bsw@905
|
322
|
bsw@905
|
323 end
|
bsw@906
|
324
|
bsw@906
|
325 hash_prefix = hash_prefix .. multirand.string(
|
bsw@906
|
326 salt_length,
|
bsw@906
|
327 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"
|
bsw@906
|
328 )
|
bsw@905
|
329
|
bsw@906
|
330 local hash = extos.crypt(password, hash_prefix)
|
bsw@905
|
331
|
bsw@905
|
332 if not hash or hash:sub(1, #hash_prefix) ~= hash_prefix then
|
bsw@905
|
333 error("Password hashing algorithm failed")
|
bsw@905
|
334 end
|
bsw@905
|
335
|
bsw/jbe@0
|
336 self.password = hash
|
bsw@1231
|
337 self.password_reset_secret = nil
|
bsw@1231
|
338 self.password_reset_secret_expiry = nil
|
bsw/jbe@0
|
339 end
|
bsw/jbe@0
|
340
|
bsw/jbe@0
|
341 function Member.object:check_password(password)
|
bsw/jbe@0
|
342 if type(password) == "string" and type(self.password) == "string" then
|
bsw@728
|
343 return extos.crypt(password, self.password) == self.password
|
bsw/jbe@0
|
344 else
|
bsw/jbe@0
|
345 return false
|
bsw/jbe@0
|
346 end
|
bsw/jbe@0
|
347 end
|
bsw/jbe@0
|
348
|
bsw@905
|
349 function Member.object_get:password_hash_needs_update()
|
bsw@905
|
350
|
bsw@905
|
351 if self.password == nil then
|
bsw@905
|
352 return nil
|
bsw@905
|
353 end
|
bsw@905
|
354
|
bsw@905
|
355 local function check_rounds(rounds)
|
bsw@905
|
356 if rounds then
|
bsw@905
|
357 rounds = tonumber(rounds)
|
bsw@905
|
358 if
|
bsw@905
|
359 rounds >= config.password_hash_min_rounds and
|
bsw@905
|
360 rounds <= config.password_hash_max_rounds
|
bsw@905
|
361 then
|
bsw@905
|
362 return false
|
bsw@905
|
363 end
|
bsw@905
|
364 end
|
bsw@905
|
365 return true
|
bsw@905
|
366 end
|
bsw@905
|
367
|
bsw@905
|
368 if config.password_hash_algorithm == "crypt_md5" then
|
bsw@905
|
369
|
bsw@905
|
370 return self.password:sub(1,3) ~= "$1$"
|
bsw@905
|
371
|
bsw@905
|
372 elseif config.password_hash_algorithm == "crypt_sha256" then
|
bsw@905
|
373
|
bsw@905
|
374 return check_rounds(self.password:match("^%$5%$rounds=([1-9][0-9]*)%$"))
|
bsw@905
|
375
|
bsw@905
|
376 elseif config.password_hash_algorithm == "crypt_sha512" then
|
bsw@905
|
377
|
bsw@905
|
378 return check_rounds(self.password:match("^%$6%$rounds=([1-9][0-9]*)%$"))
|
bsw@905
|
379
|
bsw@905
|
380 else
|
bsw@905
|
381 error("Unknown hash algorithm selected in configuration")
|
bsw@905
|
382
|
bsw@905
|
383 end
|
bsw@905
|
384
|
bsw@905
|
385 end
|
bsw@905
|
386
|
bsw/jbe@0
|
387 function Member.object_get:published_contacts()
|
bsw/jbe@0
|
388 return Member:new_selector()
|
bsw/jbe@0
|
389 :join('"contact"', nil, '"contact"."other_member_id" = "member"."id"')
|
bsw/jbe@0
|
390 :add_where{ '"contact"."member_id" = ?', self.id }
|
bsw/jbe@0
|
391 :add_where("public")
|
bsw/jbe@0
|
392 :exec()
|
bsw/jbe@0
|
393 end
|
bsw/jbe@0
|
394
|
bsw/jbe@0
|
395 function Member:by_login_and_password(login, password)
|
bsw@1071
|
396
|
bsw@1071
|
397 local function prepare_login_selector()
|
bsw@1071
|
398 local selector = self:new_selector()
|
bsw@1071
|
399 selector:add_field({ "now() > COALESCE(last_delegation_check, activated) + ?::interval", config.check_delegations_interval_hard }, "needs_delegation_check_hard")
|
bsw@1071
|
400 selector:add_where('NOT "locked"')
|
bsw@1071
|
401 selector:optional_object_mode()
|
bsw@1071
|
402 return selector
|
bsw@1071
|
403 end
|
bsw@1071
|
404
|
bsw@1071
|
405 local function do_local_login()
|
bsw@1071
|
406 local selector = prepare_login_selector()
|
bsw@1071
|
407 selector:add_where{'"login" = ?', login }
|
bsw@1071
|
408 local member = selector:exec()
|
bsw@1071
|
409 if member and member:check_password(password) then
|
bsw@1071
|
410 return member
|
bsw@1071
|
411 else
|
bsw@1071
|
412 return nil
|
bsw@1071
|
413 end
|
bsw/jbe@0
|
414 end
|
bsw@1071
|
415
|
bsw@1071
|
416 if config.ldap.member then
|
bsw@1071
|
417
|
bsw@1071
|
418 -- Let's check the users credentials against the LDAP
|
bsw@1071
|
419 local ldap_entry, ldap_err = ldap.check_credentials(login, password)
|
bsw@1071
|
420
|
bsw@1071
|
421 -- Is the user already registered as member?
|
bsw@1071
|
422 local uid
|
bsw@1071
|
423 local selector = prepare_login_selector()
|
bsw@1071
|
424
|
bsw@1071
|
425 -- Get login name from LDAP entry
|
bsw@1071
|
426 if ldap_entry then
|
bsw@1071
|
427 uid = config.ldap.member.uid_map(ldap_entry)
|
bsw@1074
|
428 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", uid }
|
bsw@1071
|
429
|
bsw@1071
|
430 -- or build it from the login
|
bsw@1071
|
431 else
|
bsw@1071
|
432 login = config.ldap.member.login_normalizer(login)
|
bsw@1074
|
433 selector:add_where{'"authority" = ? AND "authority_uid" = ?', "ldap", login }
|
bsw@1071
|
434 end
|
bsw@1071
|
435
|
bsw@1071
|
436 local member = selector:exec()
|
bsw@1071
|
437 -- The member is already registered
|
bsw@1071
|
438 if member then
|
bsw@1071
|
439
|
bsw@1071
|
440 -- The credentials entered by the user are invalid
|
bsw@1071
|
441 if ldap_err == "invalid_credentials" then
|
bsw@1071
|
442
|
bsw@1071
|
443 -- Check if the user tried a cached password (which is invalid now)
|
bsw@1071
|
444 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
445 member.password = nil
|
bsw@1071
|
446 member:save()
|
bsw@1071
|
447 end
|
bsw@1071
|
448
|
bsw@1071
|
449 -- Try a regular login
|
bsw@1071
|
450 return do_local_login()
|
bsw@1071
|
451
|
bsw@1071
|
452 end
|
bsw@1071
|
453
|
bsw@1071
|
454 -- The credentials were accepted by the LDAP server and no error occured
|
bsw@1071
|
455 if ldap_entry and not ldap_err then
|
bsw@1071
|
456
|
bsw@1071
|
457 -- Cache the password (if feature enabled)
|
bsw@1071
|
458 if config.ldap.member.cache_passwords and not member:check_password(password) then
|
bsw@1071
|
459 member:set_password(password)
|
bsw@1071
|
460 end
|
bsw@1071
|
461
|
bsw@1071
|
462 -- update the member attributes and privileges from LDAP
|
bsw@1071
|
463 local ldap_conn, ldap_err, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
464 if not err then
|
bsw@1071
|
465 local err = member:try_save()
|
bsw@1071
|
466 if err then
|
bsw@1071
|
467 return nil, "member_save_error", err
|
bsw@1071
|
468 end
|
bsw@1071
|
469 local succes, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
470 if err then
|
bsw@1071
|
471 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
472 end
|
bsw@1071
|
473 return member
|
bsw@1071
|
474 end
|
bsw@1071
|
475
|
bsw@1071
|
476 end
|
bsw@1071
|
477
|
bsw@1071
|
478 -- Some kind of LDAP error happened, if cached password are enabled,
|
bsw@1071
|
479 -- check user credentials against the cache
|
bsw@1071
|
480 if config.ldap.member.cache_passwords and member:check_password(password) then
|
bsw@1071
|
481
|
bsw@1071
|
482 -- return the successfully logged in member
|
bsw@1071
|
483 return member
|
bsw@1071
|
484
|
bsw@1071
|
485 end
|
bsw@1071
|
486
|
bsw@1071
|
487 -- The member is not registered
|
bsw@1071
|
488 elseif config.ldap.member.registration and ldap_entry and not ldap_err then
|
bsw@1071
|
489 -- Automatic registration ("auto")
|
bsw@1071
|
490 if config.ldap.member.registration == "auto" then
|
bsw@1071
|
491 member = Member:new()
|
bsw@1071
|
492 member.authority = "ldap"
|
bsw@1071
|
493 local ldap_login
|
bsw@1071
|
494 if config.ldap.member.cache_passwords then
|
bsw@1071
|
495 if config.ldap.member.login_normalizer then
|
bsw@1071
|
496 ldap_login = config.ldap.member.login_normalizer(login)
|
bsw@1071
|
497 else
|
bsw@1071
|
498 ldap_login = login
|
bsw@1071
|
499 end
|
bsw@1071
|
500 end
|
bsw@1071
|
501 -- TODO change this when SQL layers supports hstore
|
bsw@1074
|
502 member.authority_uid = uid
|
bsw@1074
|
503 member.authority_login = ldap_login
|
bsw@1071
|
504 member.activated = "now"
|
bsw@1071
|
505 member.last_activity = "now"
|
bsw@1071
|
506 if config.ldap.member.cache_passwords then
|
bsw@1071
|
507 member:set_password(password)
|
bsw@1071
|
508 end
|
bsw@1071
|
509 local ldap_conn, ldap_err, err, err2 = ldap.update_member_attr(member, nil, uid)
|
bsw@1071
|
510 if not err then
|
bsw@1071
|
511 local err = member:try_save()
|
bsw@1071
|
512 if err then
|
bsw@1071
|
513 return nil, "member_save_error", err
|
bsw@1071
|
514 end
|
bsw@1071
|
515 local success, err, err2 = ldap.update_member_privileges(member, ldap_entry)
|
bsw@1071
|
516 if err then
|
bsw@1071
|
517 return nil, "update_member_privileges_error", err, err2
|
bsw@1071
|
518 end
|
bsw@1071
|
519 return member
|
bsw@1071
|
520 end
|
bsw@1071
|
521
|
bsw@1071
|
522 -- No automatic registration
|
bsw@1071
|
523 else
|
bsw@1071
|
524 return nil, "ldap_credentials_valid_but_no_member", uid
|
bsw@1071
|
525 end
|
bsw@1071
|
526 end
|
bsw@1071
|
527
|
bsw@1071
|
528 end
|
bsw@1071
|
529
|
bsw@1071
|
530 return do_local_login()
|
bsw@1071
|
531
|
bsw/jbe@0
|
532 end
|
bsw/jbe@0
|
533
|
bsw/jbe@5
|
534 function Member:by_login(login)
|
bsw/jbe@5
|
535 local selector = self:new_selector()
|
bsw/jbe@5
|
536 selector:add_where{'"login" = ?', login }
|
bsw/jbe@5
|
537 selector:optional_object_mode()
|
bsw/jbe@5
|
538 return selector:exec()
|
bsw/jbe@5
|
539 end
|
bsw/jbe@5
|
540
|
bsw/jbe@5
|
541 function Member:by_name(name)
|
bsw/jbe@5
|
542 local selector = self:new_selector()
|
bsw/jbe@5
|
543 selector:add_where{'"name" = ?', name }
|
bsw/jbe@5
|
544 selector:optional_object_mode()
|
bsw/jbe@5
|
545 return selector:exec()
|
bsw/jbe@5
|
546 end
|
bsw/jbe@5
|
547
|
bsw@2
|
548 function Member:get_search_selector(search_string)
|
bsw/jbe@0
|
549 return self:new_selector()
|
bsw@2
|
550 :add_field( {'"highlight"("member"."name", ?)', search_string }, "name_highlighted")
|
bsw@2
|
551 :add_where{ '"member"."text_search_data" @@ "text_search_query"(?)', search_string }
|
bsw@362
|
552 :add_where("activated NOTNULL AND active")
|
bsw/jbe@0
|
553 end
|
bsw@2
|
554
|
bsw@1231
|
555 function Member.object:send_password_reset_mail()
|
bsw@1231
|
556 trace.disable()
|
bsw@1231
|
557 if not self.notify_email then
|
bsw@1231
|
558 return false
|
bsw@1231
|
559 end
|
jbe@1232
|
560 self.password_reset_secret = secret_token()
|
bsw@1231
|
561 local expiry = db:query("SELECT now() + '1 days'::interval as expiry", "object").expiry
|
bsw@1231
|
562 self.password_reset_secret_expiry = expiry
|
bsw@1231
|
563 self:save()
|
bsw@1231
|
564 local content = slot.use_temporary(function()
|
bsw@1231
|
565 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw@1231
|
566 slot.put(_"to reset your password please click on the following link:\n\n")
|
bsw@1231
|
567 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html?secret=" .. self.password_reset_secret .. "\n\n")
|
bsw@1231
|
568 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw@1231
|
569 slot.put(request.get_absolute_baseurl() .. "index/reset_password.html\n\n")
|
bsw@1231
|
570 slot.put(_"On that page please enter the reset code:\n\n")
|
bsw@1231
|
571 slot.put(self.password_reset_secret .. "\n\n")
|
bsw@1231
|
572 end)
|
bsw@1231
|
573 local success = net.send_mail{
|
bsw@1231
|
574 envelope_from = config.mail_envelope_from,
|
bsw@1231
|
575 from = config.mail_from,
|
bsw@1231
|
576 reply_to = config.mail_reply_to,
|
bsw@1231
|
577 to = self.notify_email,
|
bsw@1231
|
578 subject = config.mail_subject_prefix .. _"Password reset request",
|
bsw@1231
|
579 content_type = "text/plain; charset=UTF-8",
|
bsw@1231
|
580 content = content
|
bsw@1231
|
581 }
|
bsw@1231
|
582 return success
|
bsw@1231
|
583 end
|
bsw@1231
|
584
|
bsw@388
|
585 function Member.object:send_invitation(template_file, subject)
|
bsw@286
|
586 trace.disable()
|
jbe@1232
|
587 self.invite_code = secret_token()
|
bsw@388
|
588 self:save()
|
bsw@388
|
589
|
bsw@388
|
590 local subject = subject
|
bsw@388
|
591 local content
|
bsw@388
|
592
|
bsw@388
|
593 if template_file then
|
bsw@388
|
594 local fh = io.open(template_file, "r")
|
bsw@388
|
595 content = fh:read("*a")
|
bsw@388
|
596 content = (content:gsub("#{invite_code}", self.invite_code))
|
bsw@388
|
597 else
|
bsw@388
|
598 subject = config.mail_subject_prefix .. _"Invitation to LiquidFeedback"
|
bsw@388
|
599 content = slot.use_temporary(function()
|
bsw@388
|
600 slot.put(_"Hello\n\n")
|
bsw@388
|
601 slot.put(_"You are invited to LiquidFeedback. To register please click the following link:\n\n")
|
bsw@388
|
602 slot.put(request.get_absolute_baseurl() .. "index/register.html?invite=" .. self.invite_code .. "\n\n")
|
bsw@388
|
603 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
bsw@388
|
604 slot.put(request.get_absolute_baseurl() .. "index/register.html\n\n")
|
bsw@388
|
605 slot.put(_"On that page please enter the invite key:\n\n")
|
bsw@388
|
606 slot.put(self.invite_code .. "\n\n")
|
bsw@388
|
607 end)
|
bsw@388
|
608 end
|
bsw@388
|
609
|
bsw@286
|
610 local success = net.send_mail{
|
bsw@286
|
611 envelope_from = config.mail_envelope_from,
|
bsw@286
|
612 from = config.mail_from,
|
bsw@286
|
613 reply_to = config.mail_reply_to,
|
bsw@286
|
614 to = self.notify_email_unconfirmed or self.notify_email,
|
bsw@388
|
615 subject = subject,
|
bsw@286
|
616 content_type = "text/plain; charset=UTF-8",
|
bsw@286
|
617 content = content
|
bsw@286
|
618 }
|
bsw@286
|
619 return success
|
bsw/jbe@0
|
620 end
|
bsw@2
|
621
|
bsw/jbe@6
|
622 function Member.object:set_notify_email(notify_email)
|
bsw@224
|
623 trace.disable()
|
bsw/jbe@6
|
624 local expiry = db:query("SELECT now() + '7 days'::interval as expiry", "object").expiry
|
bsw/jbe@6
|
625 self.notify_email_unconfirmed = notify_email
|
jbe@1232
|
626 self.notify_email_secret = secret_token()
|
bsw/jbe@6
|
627 self.notify_email_secret_expiry = expiry
|
bsw/jbe@6
|
628 local content = slot.use_temporary(function()
|
bsw/jbe@6
|
629 slot.put(_"Hello " .. self.name .. ",\n\n")
|
bsw/jbe@6
|
630 slot.put(_"Please confirm your email address by clicking the following link:\n\n")
|
jbe@326
|
631 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html?secret=" .. self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
632 slot.put(_"If this link is not working, please open following url in your web browser:\n\n")
|
jbe@326
|
633 slot.put(request.get_absolute_baseurl() .. "index/confirm_notify_email.html\n\n")
|
bsw/jbe@6
|
634 slot.put(_"On that page please enter the confirmation code:\n\n")
|
bsw/jbe@6
|
635 slot.put(self.notify_email_secret .. "\n\n")
|
bsw/jbe@6
|
636 end)
|
bsw/jbe@6
|
637 local success = net.send_mail{
|
bsw/jbe@6
|
638 envelope_from = config.mail_envelope_from,
|
bsw/jbe@6
|
639 from = config.mail_from,
|
bsw/jbe@6
|
640 reply_to = config.mail_reply_to,
|
bsw/jbe@6
|
641 to = self.notify_email_unconfirmed,
|
bsw/jbe@6
|
642 subject = config.mail_subject_prefix .. _"Email confirmation request",
|
bsw/jbe@6
|
643 content_type = "text/plain; charset=UTF-8",
|
bsw/jbe@6
|
644 content = content
|
bsw/jbe@6
|
645 }
|
bsw@75
|
646 if success then
|
bsw@75
|
647 local lock_expiry = db:query("SELECT now() + '1 hour'::interval AS lock_expiry", "object").lock_expiry
|
bsw@75
|
648 self.notify_email_lock_expiry = lock_expiry
|
bsw@75
|
649 end
|
bsw@75
|
650 self:save()
|
bsw/jbe@6
|
651 return success
|
bsw/jbe@6
|
652 end
|
bsw@11
|
653
|
bsw/jbe@19
|
654 function Member.object:get_setting(key)
|
bsw@79
|
655 return Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
656 end
|
bsw/jbe@19
|
657
|
bsw/jbe@19
|
658 function Member.object:get_setting_value(key)
|
bsw@79
|
659 local setting = Setting:by_pk(self.id, key)
|
bsw/jbe@19
|
660 if setting then
|
bsw/jbe@19
|
661 return setting.value
|
bsw/jbe@19
|
662 end
|
bsw@11
|
663 end
|
bsw@11
|
664
|
bsw@11
|
665 function Member.object:set_setting(key, value)
|
bsw/jbe@19
|
666 local setting = self:get_setting(key)
|
bsw/jbe@19
|
667 if not setting then
|
bsw/jbe@19
|
668 setting = Setting:new()
|
bsw@79
|
669 setting.member_id = self.id
|
bsw/jbe@19
|
670 setting.key = key
|
bsw/jbe@19
|
671 end
|
bsw/jbe@19
|
672 setting.value = value
|
bsw/jbe@19
|
673 setting:save()
|
bsw@11
|
674 end
|
bsw@11
|
675
|
bsw@11
|
676 function Member.object:get_setting_maps_by_key(key)
|
bsw@11
|
677 return SettingMap:new_selector()
|
bsw@11
|
678 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
679 :add_where{ "key = ?", key }
|
bsw@11
|
680 :add_order_by("subkey")
|
bsw@11
|
681 :exec()
|
bsw@11
|
682 end
|
bsw@11
|
683
|
bsw@11
|
684 function Member.object:get_setting_map_by_key_and_subkey(key, subkey)
|
bsw@11
|
685 return SettingMap:new_selector()
|
bsw@11
|
686 :add_where{ "member_id = ?", self.id }
|
bsw@11
|
687 :add_where{ "key = ?", key }
|
bsw@11
|
688 :add_where{ "subkey = ?", subkey }
|
bsw@11
|
689 :add_order_by("subkey")
|
bsw@11
|
690 :optional_object_mode()
|
bsw@11
|
691 :exec()
|
bsw@11
|
692 end
|
bsw@11
|
693
|
bsw@11
|
694 function Member.object:set_setting_map(key, subkey, value)
|
poelzi@144
|
695 setting_map = self:get_setting_map_by_key_and_subkey(key, subkey)
|
poelzi@144
|
696 if not setting_map then
|
poelzi@144
|
697 setting_map = SettingMap:new()
|
poelzi@144
|
698 setting_map.member_id = self.id
|
poelzi@144
|
699 setting_map.key = key
|
poelzi@144
|
700 setting_map.subkey = subkey
|
poelzi@144
|
701 end
|
poelzi@144
|
702 setting_map.value = value
|
poelzi@144
|
703 setting_map:save()
|
bsw@11
|
704 end
|
bsw@75
|
705
|
bsw@75
|
706 function Member.object_get:notify_email_locked()
|
bsw@75
|
707 return(
|
bsw@75
|
708 Member:new_selector()
|
bsw@75
|
709 :add_where{ "id = ?", app.session.member.id }
|
bsw@75
|
710 :add_where("notify_email_lock_expiry > now()")
|
bsw@75
|
711 :count() == 1
|
bsw@75
|
712 )
|
poelzi@134
|
713 end
|
poelzi@134
|
714
|
bsw@273
|
715 function Member.object_get:units_with_voting_right()
|
bsw@273
|
716 return(Unit:new_selector()
|
bsw@273
|
717 :join("privilege", nil, { "privilege.unit_id = unit.id AND privilege.member_id = ? AND privilege.voting_right", self.id })
|
bsw@273
|
718 :exec()
|
bsw@273
|
719 )
|
bsw@273
|
720 end
|
bsw@273
|
721
|
poelzi@134
|
722 function Member.object:ui_field_text(args)
|
poelzi@134
|
723 args = args or {}
|
bsw@813
|
724 if app.session:has_access("authors_pseudonymous") then
|
poelzi@134
|
725 -- ugly workaround for getting html into a replaced string and to the user
|
poelzi@134
|
726 ui.container{label = args.label, label_attr={class="ui_field_label"}, content = function()
|
poelzi@134
|
727 slot.put(string.format('<span><a href="%s">%s</a></span>',
|
poelzi@134
|
728 encode.url{
|
poelzi@134
|
729 module = "member",
|
poelzi@134
|
730 view = "show",
|
poelzi@134
|
731 id = self.id,
|
poelzi@134
|
732 },
|
poelzi@134
|
733 encode.html(self.name)))
|
poelzi@134
|
734 end
|
poelzi@134
|
735 }
|
poelzi@134
|
736 else
|
poelzi@134
|
737 ui.field.text{ label = args.label, value = _"[not displayed public]" }
|
poelzi@134
|
738 end
|
poelzi@134
|
739 end
|
bsw@281
|
740
|
bsw@281
|
741 function Member.object:has_voting_right_for_unit_id(unit_id)
|
bsw@547
|
742 if not self.__units_with_voting_right_hash then
|
bsw@547
|
743 local privileges = Privilege:new_selector()
|
bsw@547
|
744 :add_where{ "member_id = ?", self.id }
|
bsw@547
|
745 :add_where("voting_right")
|
bsw@547
|
746 :exec()
|
bsw@547
|
747 self.__units_with_voting_right_hash = {}
|
bsw@551
|
748 for i, privilege in ipairs(privileges) do
|
bsw@551
|
749 self.__units_with_voting_right_hash[privilege.unit_id] = true
|
bsw@551
|
750 end
|
bsw@547
|
751 end
|
bsw@547
|
752 return self.__units_with_voting_right_hash[unit_id] and true or false
|
jbe@326
|
753 end
|
bsw@525
|
754
|
bsw@894
|
755 function Member.object:has_polling_right_for_unit_id(unit_id)
|
bsw@894
|
756 if not self.__units_with_polling_right_hash then
|
bsw@894
|
757 local privileges = Privilege:new_selector()
|
bsw@894
|
758 :add_where{ "member_id = ?", self.id }
|
bsw@894
|
759 :add_where("polling_right")
|
bsw@894
|
760 :exec()
|
bsw@894
|
761 self.__units_with_polling_right_hash = {}
|
bsw@894
|
762 for i, privilege in ipairs(privileges) do
|
bsw@894
|
763 self.__units_with_polling_right_hash[privilege.unit_id] = true
|
bsw@894
|
764 end
|
bsw@894
|
765 end
|
bsw@894
|
766 return self.__units_with_polling_right_hash[unit_id] and true or false
|
bsw@894
|
767 end
|
bsw@894
|
768
|
bsw@525
|
769 function Member.object:get_delegatee_member(unit_id, area_id, issue_id)
|
bsw@525
|
770 local selector = Member:new_selector()
|
bsw@525
|
771 if unit_id then
|
bsw@525
|
772 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
|
773 end
|
bsw@525
|
774 selector:optional_object_mode()
|
bsw@525
|
775 return selector:exec()
|
bsw@533
|
776 end
|
bsw@929
|
777
|
bsw@1088
|
778 function Member.object:delete()
|
bsw@1088
|
779 db:query{ "SELECT delete_member(?)", self.id }
|
bsw@1088
|
780 end
|