liquid_feedback_frontend

annotate model/member.lua @ 1201:ccc357ccb68c

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

Impressum / About Us