liquid_feedback_frontend
changeset 6:8d91bccab0bf beta2
Version beta2
Possibility to browse voters of a closed issue
Registration with invite code
Email confirmation and password recovery
Download function (for database dumps) added
Critical bug solved, which made it impossible to select your opinion on other peoples suggestions
Catching error, when trying to set an opinion on a suggestion which has been meanwhile deleted
Fixed wrong sorting order for "supporters" or "potential supporters"
Added format info for birthday (Error when entering dates in wrong format is NOT fixed in this release)
Strip space characters from certain fields and ensure they contain at least 3 characters
Showing grade in opinion/list as clear text instead of integer value
More information on initiative is displayed while voting
Colored notification box shown on pages of issues or initiatives which are currently in voting state
Changed default filter for issues to "Open"
Back link on suggestion page
Some optical changes
Removed wrong space character in LICENSE file
Possibility to browse voters of a closed issue
Registration with invite code
Email confirmation and password recovery
Download function (for database dumps) added
Critical bug solved, which made it impossible to select your opinion on other peoples suggestions
Catching error, when trying to set an opinion on a suggestion which has been meanwhile deleted
Fixed wrong sorting order for "supporters" or "potential supporters"
Added format info for birthday (Error when entering dates in wrong format is NOT fixed in this release)
Strip space characters from certain fields and ensure they contain at least 3 characters
Showing grade in opinion/list as clear text instead of integer value
More information on initiative is displayed while voting
Colored notification box shown on pages of issues or initiatives which are currently in voting state
Changed default filter for issues to "Open"
Back link on suggestion page
Some optical changes
Removed wrong space character in LICENSE file
line diff
1.1 --- a/LICENSE Fri Dec 25 12:00:00 2009 +0100 1.2 +++ b/LICENSE Sat Jan 02 12:00:00 2010 +0100 1.3 @@ -21,7 +21,7 @@ 1.4 1.5 3rd party license information: 1.6 1.7 -The icons used in Liquid Feedback (except national flags) are from Silk 1.8 +The icons used in LiquidFeedback (except national flags) are from Silk 1.9 icon set 1.3 by Mark James. [ http://www.famfamfam.com/lab/icons/silk/ ] 1.10 His work is licensed under a Creative Commons Attribution 2.5 License. 1.11 -[ http://creativecommons.org/licenses/by/2.5/ ] 1.12 \ No newline at end of file 1.13 +[ http://creativecommons.org/licenses/by/2.5/ ]
2.1 --- a/app/main/_filter/21_auth.lua Fri Dec 25 12:00:00 2009 +0100 2.2 +++ b/app/main/_filter/21_auth.lua Sat Jan 02 12:00:00 2010 +0100 2.3 @@ -6,6 +6,10 @@ 2.4 or request.get_view() == "register" 2.5 or request.get_action() == "register" 2.6 or request.get_view() == "about" 2.7 + or request.get_view() == "reset_password" 2.8 + or request.get_action() == "reset_password" 2.9 + or request.get_view() == "confirm_notify_email" 2.10 + or request.get_action() == "confirm_notify_email" 2.11 ) 2.12 ) 2.13
3.1 --- a/app/main/_filter_view/30_navigation.lua Fri Dec 25 12:00:00 2009 +0100 3.2 +++ b/app/main/_filter_view/30_navigation.lua Sat Jan 02 12:00:00 2010 +0100 3.3 @@ -21,6 +21,14 @@ 3.4 } 3.5 ui.link{ 3.6 content = function() 3.7 + ui.image{ static = "icons/16/key_forgot.png" } 3.8 + slot.put(_"Reset password") 3.9 + end, 3.10 + module = 'index', 3.11 + view = 'reset_password' 3.12 + } 3.13 + ui.link{ 3.14 + content = function() 3.15 ui.image{ static = "icons/16/information.png" } 3.16 slot.put('About / Impressum') 3.17 end, 3.18 @@ -79,15 +87,6 @@ 3.19 view = 'about' 3.20 } 3.21 3.22 - ui.link{ 3.23 - content = function() 3.24 - ui.image{ static = "icons/16/bug.png" } 3.25 - slot.put(_"Bug report") 3.26 - end, 3.27 - external = "http://trac.public-software-group.org/projects/lf" --/newticket?description=" .. encode.url_part("\n\n\n\nReport for: " .. os.getenv("REQUEST_URI") ) 3.28 - } 3.29 - 3.30 - 3.31 if app.session.member.admin then 3.32 3.33 slot.put(" ")
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/app/main/index/_action/confirm_notify_email.lua Sat Jan 02 12:00:00 2010 +0100 4.3 @@ -0,0 +1,18 @@ 4.4 +local secret = param.get("secret") 4.5 + 4.6 +local member = Member:new_selector() 4.7 + :add_where{ "notify_email_secret = ?", secret } 4.8 + :add_where("notify_email_secret_expiry > now()") 4.9 + :optional_object_mode() 4.10 + :exec() 4.11 + 4.12 +if member then 4.13 + member.notify_email = member.notify_email_unconfirmed 4.14 + member.notify_email_unconfirmed = nil 4.15 + member.notify_email_secret = nil 4.16 + member:save() 4.17 + slot.put_into("notice", _"Email address is confirmed now") 4.18 +else 4.19 + slot.put_into("error", _"Confirmation code invalid!") 4.20 + return false 4.21 +end
5.1 --- a/app/main/index/_action/register.lua Fri Dec 25 12:00:00 2009 +0100 5.2 +++ b/app/main/index/_action/register.lua Sat Jan 02 12:00:00 2010 +0100 5.3 @@ -10,10 +10,20 @@ 5.4 return false 5.5 end 5.6 5.7 -local name = param.get("name") 5.8 +local notify_email = param.get("notify_email") 5.9 5.10 -if invite_code and not name then 5.11 - slot.put_into("notice", _"Invite code valid!") 5.12 +if invite_code and not notify_email then 5.13 + request.redirect{ 5.14 + mode = "redirect", 5.15 + module = "index", 5.16 + view = "register", 5.17 + params = { code = invite_code.code } 5.18 + } 5.19 + return false 5.20 +end 5.21 + 5.22 +if #notify_email < 5 then 5.23 + slot.put_into("error", _"Email address too short!") 5.24 request.redirect{ 5.25 mode = "redirect", 5.26 module = "index", 5.27 @@ -23,13 +33,47 @@ 5.28 return false 5.29 end 5.30 5.31 +local name = param.get("name") 5.32 + 5.33 +if notify_email and not name then 5.34 + request.redirect{ 5.35 + mode = "redirect", 5.36 + module = "index", 5.37 + view = "register", 5.38 + params = { 5.39 + code = invite_code.code, 5.40 + notify_email = notify_email 5.41 + } 5.42 + } 5.43 + return false 5.44 +end 5.45 + 5.46 +name = util.trim(name) 5.47 + 5.48 +if #name < 3 then 5.49 + slot.put_into("error", _"This username is too short!") 5.50 + request.redirect{ 5.51 + mode = "redirect", 5.52 + module = "index", 5.53 + view = "register", 5.54 + params = { 5.55 + code = invite_code.code, 5.56 + notify_email = notify_email 5.57 + } 5.58 + } 5.59 + return false 5.60 +end 5.61 + 5.62 if Member:by_name(name) then 5.63 slot.put_into("error", _"This name is already taken, please choose another one!") 5.64 request.redirect{ 5.65 mode = "redirect", 5.66 module = "index", 5.67 view = "register", 5.68 - params = { code = invite_code.code } 5.69 + params = { 5.70 + code = invite_code.code, 5.71 + notify_email = notify_email 5.72 + } 5.73 } 5.74 return false 5.75 end 5.76 @@ -37,13 +81,30 @@ 5.77 local login = param.get("login") 5.78 5.79 if name and not login then 5.80 - slot.put_into("notice", _"Name is available") 5.81 request.redirect{ 5.82 mode = "redirect", 5.83 module = "index", 5.84 view = "register", 5.85 params = { 5.86 code = invite_code.code, 5.87 + notify_email = notify_email, 5.88 + name = name 5.89 + } 5.90 + } 5.91 + return false 5.92 +end 5.93 + 5.94 +login = util.trim(login) 5.95 + 5.96 +if #login < 3 then 5.97 + slot.put_into("error", _"This login is too short!") 5.98 + request.redirect{ 5.99 + mode = "redirect", 5.100 + module = "index", 5.101 + view = "register", 5.102 + params = { 5.103 + code = invite_code.code, 5.104 + notify_email = notify_email, 5.105 name = name 5.106 } 5.107 } 5.108 @@ -58,23 +119,57 @@ 5.109 view = "register", 5.110 params = { 5.111 code = invite_code.code, 5.112 + notify_email = notify_email, 5.113 name = name 5.114 } 5.115 } 5.116 return false 5.117 end 5.118 5.119 +local use_terms_accepted = param.get("use_terms_accepted", atom.boolean) 5.120 + 5.121 +if login and use_terms_accepted == nil then 5.122 + request.redirect{ 5.123 + mode = "redirect", 5.124 + module = "index", 5.125 + view = "register", 5.126 + params = { 5.127 + code = invite_code.code, 5.128 + notify_email = notify_email, 5.129 + name = name, 5.130 + login = login 5.131 + } 5.132 + } 5.133 + return false 5.134 +end 5.135 + 5.136 +if use_terms_accepted ~= true then 5.137 + slot.put_into("error", _"You have to accept the terms of use to complete registration.") 5.138 + request.redirect{ 5.139 + mode = "redirect", 5.140 + module = "index", 5.141 + view = "register", 5.142 + params = { 5.143 + code = invite_code.code, 5.144 + notify_email = notify_email, 5.145 + name = name, 5.146 + login = login 5.147 + } 5.148 + } 5.149 + return false 5.150 +end 5.151 + 5.152 local password1 = param.get("password1") 5.153 local password2 = param.get("password2") 5.154 5.155 if login and not password1 then 5.156 - slot.put_into("notice", _"Login is available") 5.157 request.redirect{ 5.158 mode = "redirect", 5.159 module = "index", 5.160 view = "register", 5.161 params = { 5.162 code = invite_code.code, 5.163 + notify_email = notify_email, 5.164 name = name, 5.165 login = login 5.166 } 5.167 @@ -90,6 +185,7 @@ 5.168 view = "register", 5.169 params = { 5.170 code = invite_code.code, 5.171 + notify_email = notify_email, 5.172 name = name, 5.173 login = login 5.174 } 5.175 @@ -105,6 +201,7 @@ 5.176 view = "register", 5.177 params = { 5.178 code = invite_code.code, 5.179 + notify_email = notify_email, 5.180 name = name, 5.181 login = login 5.182 } 5.183 @@ -116,6 +213,24 @@ 5.184 5.185 member.login = login 5.186 member.name = name 5.187 + 5.188 +local success = member:set_notify_email(notify_email) 5.189 +if not success then 5.190 + slot.put_into("error", _"Can't send confirmation email") 5.191 + request.redirect{ 5.192 + mode = "redirect", 5.193 + module = "index", 5.194 + view = "register", 5.195 + params = { 5.196 + code = invite_code.code, 5.197 + notify_email = notify_email, 5.198 + name = name, 5.199 + login = login 5.200 + } 5.201 + } 5.202 + return 5.203 +end 5.204 + 5.205 member:set_password(password1) 5.206 member:save() 5.207 5.208 @@ -125,8 +240,8 @@ 5.209 5.210 slot.put_into("notice", _"You've successfully registered and you can login now with your login and password!") 5.211 5.212 - request.redirect{ 5.213 - mode = "redirect", 5.214 - module = "index", 5.215 - view = "login", 5.216 - } 5.217 +request.redirect{ 5.218 + mode = "redirect", 5.219 + module = "index", 5.220 + view = "login", 5.221 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/app/main/index/_action/reset_password.lua Sat Jan 02 12:00:00 2010 +0100 6.3 @@ -0,0 +1,74 @@ 6.4 +local secret = param.get("secret") 6.5 + 6.6 +if not secret then 6.7 + 6.8 + local member = Member:new_selector() 6.9 + :add_where{ "login = ?", param.get("login") } 6.10 + :add_where("password_reset_secret ISNULL OR password_reset_secret_expiry < now()") 6.11 + :optional_object_mode() 6.12 + :exec() 6.13 + 6.14 + if member then 6.15 + if not member.notify_email then 6.16 + slot.put_into("error", _"Sorry, but there is not confirmed email address for your account. Please contact the administrator or support.") 6.17 + return false 6.18 + end 6.19 + member.password_reset_secret = multirand.string( 24, "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ) 6.20 + local expiry = db:query("SELECT now() + '1 days'::interval as expiry", "object").expiry 6.21 + member.password_reset_secret_expiry = expiry 6.22 + member:save() 6.23 + local content = slot.use_temporary(function() 6.24 + slot.put(_"Hello " .. member.name .. ",\n\n") 6.25 + slot.put(_"to reset your password please click on the following link:\n\n") 6.26 + slot.put(config.absolute_base_url .. "index/reset_password.html?secret=" .. member.password_reset_secret .. "\n\n") 6.27 + slot.put(_"If this link is not working, please open following url in your web browser:\n\n") 6.28 + slot.put(config.absolute_base_url .. "index/reset_password.html\n\n") 6.29 + slot.put(_"On that page please enter the reset code:\n\n") 6.30 + slot.put(member.password_reset_secret .. "\n\n") 6.31 + end) 6.32 + local success = net.send_mail{ 6.33 + envelope_from = config.mail_envelope_from, 6.34 + from = config.mail_from, 6.35 + reply_to = config.mail_reply_to, 6.36 + to = member.notify_email, 6.37 + subject = config.mail_subject_prefix .. _"Password reset request", 6.38 + content_type = "text/plain; charset=UTF-8", 6.39 + content = content 6.40 + } 6.41 + end 6.42 + 6.43 + slot.put_into("notice", _"Reset link has been send for this member") 6.44 + 6.45 +else 6.46 + local member = Member:new_selector() 6.47 + :add_where{ "password_reset_secret = ?", secret } 6.48 + :add_where{ "password_reset_secret_expiry > now()" } 6.49 + :optional_object_mode() 6.50 + :exec() 6.51 + 6.52 + if not member then 6.53 + slot.put_into("error", _"Reset code is invalid!") 6.54 + return false 6.55 + end 6.56 + 6.57 + local password1 = param.get("password1") 6.58 + local password2 = param.get("password2") 6.59 + 6.60 + if password1 ~= password2 then 6.61 + slot.put_into("error", _"Passwords don't match!") 6.62 + return false 6.63 + end 6.64 + 6.65 + if #password1 < 8 then 6.66 + slot.put_into("error", _"Passwords must consist of at least 8 characters!") 6.67 + return false 6.68 + end 6.69 + 6.70 + member:set_password(password1) 6.71 + member.password_reset_secret = nil 6.72 + member.password_reset_secret_expiry = nil 6.73 + member:save() 6.74 + 6.75 + slot.put_into("notice", _"Password has been reset successfully") 6.76 + 6.77 +end 6.78 \ No newline at end of file
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/app/main/index/confirm_notify_email.lua Sat Jan 02 12:00:00 2010 +0100 7.3 @@ -0,0 +1,22 @@ 7.4 +slot.put_into("title", _"Email address confirmation") 7.5 + 7.6 +ui.form{ 7.7 + attr = { class = "vertical" }, 7.8 + module = "index", 7.9 + action = "confirm_notify_email", 7.10 + routing = { 7.11 + ok = { 7.12 + mode = "redirect", 7.13 + module = "index", 7.14 + view = "index" 7.15 + } 7.16 + }, 7.17 + content = function() 7.18 + ui.field.text{ 7.19 + label = _"Confirmation code", 7.20 + name = "secret", 7.21 + value = param.get("secret") 7.22 + } 7.23 + ui.submit{ text = _"Confirm" } 7.24 + end 7.25 +} 7.26 \ No newline at end of file
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/app/main/index/download.lua Sat Jan 02 12:00:00 2010 +0100 8.3 @@ -0,0 +1,60 @@ 8.4 +if not config.download_dir then 8.5 + error("feature not enabled") 8.6 +end 8.7 + 8.8 +slot.put_into("title", _"Download database export") 8.9 + 8.10 +slot.select("actions", function() 8.11 + ui.link{ 8.12 + content = function() 8.13 + ui.image{ static = "icons/16/cancel.png" } 8.14 + slot.put(_"Cancel") 8.15 + end, 8.16 + module = "index", 8.17 + view = "index" 8.18 + } 8.19 +end) 8.20 + 8.21 +util.help("index.download", _"Download") 8.22 + 8.23 +ui.container{ 8.24 + attr = { class = "wiki use_terms" }, 8.25 + content = function() 8.26 + slot.put(format.wiki_text(config.download_use_terms)) 8.27 + end 8.28 +} 8.29 + 8.30 + 8.31 +local file_list = os.listdir(config.download_dir) 8.32 + 8.33 +local tmp = {} 8.34 +for i, filename in ipairs(file_list) do 8.35 + if not filename:find("^%.") then 8.36 + tmp[#tmp+1] = filename 8.37 + end 8.38 +end 8.39 + 8.40 +local file_list = tmp 8.41 + 8.42 +table.sort(file_list, function(a, b) return a > b end) 8.43 + 8.44 +ui.list{ 8.45 + records = file_list, 8.46 + columns = { 8.47 + { 8.48 + content = function(filename) 8.49 + slot.put(encode.html(filename)) 8.50 + end 8.51 + }, 8.52 + { 8.53 + content = function(filename) 8.54 + ui.link{ 8.55 + content = _"Download", 8.56 + module = "index", 8.57 + view = "download_file", 8.58 + params = { filename = filename } 8.59 + } 8.60 + end 8.61 + } 8.62 + } 8.63 +} 8.64 \ No newline at end of file
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/app/main/index/download_file.lua Sat Jan 02 12:00:00 2010 +0100 9.3 @@ -0,0 +1,15 @@ 9.4 +if not config.download_dir then 9.5 + error("feature not enabled") 9.6 +end 9.7 + 9.8 +local filename = param.get("filename") 9.9 + 9.10 +local file = assert(io.open(encode.file_path(config.download_dir, filename)), "file not found") 9.11 + 9.12 +print('Content-type: application/octet-stream') 9.13 +print('Content-disposition: attachment; filename=' .. filename) 9.14 +print('') 9.15 + 9.16 +io.stdout:write(file:read("*a")) 9.17 + 9.18 +exit()
10.1 --- a/app/main/index/index.lua Fri Dec 25 12:00:00 2009 +0100 10.2 +++ b/app/main/index/index.lua Sat Jan 02 12:00:00 2010 +0100 10.3 @@ -75,6 +75,16 @@ 10.4 view = "change_password" 10.5 } 10.6 10.7 + if config.download_dir then 10.8 + ui.link{ 10.9 + content = function() 10.10 + ui.image{ static = "icons/16/database_save.png" } 10.11 + slot.put(_"Download") 10.12 + end, 10.13 + module = "index", 10.14 + view = "download" 10.15 + } 10.16 + end 10.17 end) 10.18 10.19 local lang = locale.get("lang")
11.1 --- a/app/main/index/register.lua Fri Dec 25 12:00:00 2009 +0100 11.2 +++ b/app/main/index/register.lua Sat Jan 02 12:00:00 2010 +0100 11.3 @@ -1,32 +1,26 @@ 11.4 slot.put_into("title", _"Registration") 11.5 11.6 -slot.select("actions", function() 11.7 - ui.link{ 11.8 - content = function() 11.9 - ui.image{ static = "icons/16/cancel.png" } 11.10 - slot.put(_"Cancel") 11.11 - end, 11.12 - module = "index", 11.13 - view = "index" 11.14 - } 11.15 -end) 11.16 11.17 local code = param.get("code") 11.18 +local notify_email = param.get("notify_email") 11.19 local name = param.get("name") 11.20 local login = param.get("login") 11.21 11.22 +slot.put_into("title", " (") 11.23 ui.form{ 11.24 - attr = { class = "login" }, 11.25 + attr = { class = "vertical" }, 11.26 module = 'index', 11.27 action = 'register', 11.28 params = { 11.29 code = code, 11.30 + notify_email = notify_email, 11.31 name = name, 11.32 login = login 11.33 }, 11.34 content = function() 11.35 11.36 if not code then 11.37 + slot.put_into("title", _"Step 1/5: Invite code") 11.38 ui.tag{ 11.39 tag = "p", 11.40 content = _"Please enter the invite code you've received." 11.41 @@ -34,9 +28,48 @@ 11.42 ui.field.text{ 11.43 label = _'Invite code', 11.44 name = 'code', 11.45 + value = param.get("invite") 11.46 + } 11.47 + 11.48 + elseif not notify_email then 11.49 + slot.put_into("title", _"Step 2/5: Email address") 11.50 + slot.select("actions", function() 11.51 + ui.link{ 11.52 + content = function() 11.53 + ui.image{ static = "icons/16/resultset_previous.png" } 11.54 + slot.put(_"One step back") 11.55 + end, 11.56 + module = "index", 11.57 + view = "register", 11.58 + params = { 11.59 + } 11.60 + } 11.61 + end) 11.62 + ui.tag{ 11.63 + tag = "p", 11.64 + content = _"Please enter your email address. This address will be used for automatic notifications (if you request them) and in case you've lost your password. This address will not be published. After registration you will receive an email with a confirmation link." 11.65 + } 11.66 + ui.field.text{ 11.67 + label = _'Email address', 11.68 + name = 'notify_email', 11.69 + value = param.get("notify_email") 11.70 } 11.71 11.72 elseif not name then 11.73 + slot.put_into("title", _"Step 3/5: Username") 11.74 + slot.select("actions", function() 11.75 + ui.link{ 11.76 + content = function() 11.77 + ui.image{ static = "icons/16/resultset_previous.png" } 11.78 + slot.put(_"One step back") 11.79 + end, 11.80 + module = "index", 11.81 + view = "register", 11.82 + params = { 11.83 + code = code 11.84 + } 11.85 + } 11.86 + end) 11.87 ui.tag{ 11.88 tag = "p", 11.89 content = _"Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you. You CAN'T change this name later, so please choose it wisely!" 11.90 @@ -48,6 +81,21 @@ 11.91 } 11.92 11.93 elseif not login then 11.94 + slot.put_into("title", _"Step 4/5: Login name") 11.95 + slot.select("actions", function() 11.96 + ui.link{ 11.97 + content = function() 11.98 + ui.image{ static = "icons/16/resultset_previous.png" } 11.99 + slot.put(_"One step back") 11.100 + end, 11.101 + module = "index", 11.102 + view = "register", 11.103 + params = { 11.104 + code = code, 11.105 + notify_email = notify_email 11.106 + } 11.107 + } 11.108 + end) 11.109 ui.tag{ 11.110 tag = "p", 11.111 content = _"Please choose a login name. This name will not be shown to others and is used only by you to login into the system. The login name is case sensitive." 11.112 @@ -59,18 +107,54 @@ 11.113 } 11.114 11.115 else 11.116 + slot.put_into("title", _"Step 5/5: Terms of use and password") 11.117 + slot.select("actions", function() 11.118 + ui.link{ 11.119 + content = function() 11.120 + ui.image{ static = "icons/16/resultset_previous.png" } 11.121 + slot.put(_"One step back") 11.122 + end, 11.123 + module = "index", 11.124 + view = "register", 11.125 + params = { 11.126 + code = code, 11.127 + notify_email = notify_email, 11.128 + name = name, 11.129 + } 11.130 + } 11.131 + end) 11.132 + ui.container{ 11.133 + attr = { class = "wiki use_terms" }, 11.134 + content = function() 11.135 + slot.put(format.wiki_text(config.use_terms)) 11.136 + end 11.137 + } 11.138 + slot.put("<br />") 11.139 + ui.field.text{ 11.140 + label = _'Email address', 11.141 + value = param.get("notify_email"), 11.142 + readonly = true 11.143 + } 11.144 ui.field.text{ 11.145 label = _'Name', 11.146 - name = 'name', 11.147 value = param.get("name"), 11.148 readonly = true 11.149 } 11.150 ui.field.text{ 11.151 label = _'Login name', 11.152 - name = 'login', 11.153 value = param.get("login"), 11.154 readonly = true 11.155 } 11.156 + 11.157 + ui.tag{ 11.158 + tag = "p", 11.159 + content = _"I accept the terms of use by checking the following checkbox:" 11.160 + } 11.161 + ui.field.boolean{ 11.162 + label = _"Terms accepted", 11.163 + name = "use_terms_accepted", 11.164 + } 11.165 + 11.166 ui.tag{ 11.167 tag = "p", 11.168 content = _"Please choose a password and enter it twice. The password is case sensitive." 11.169 @@ -90,6 +174,18 @@ 11.170 text = _'Register' 11.171 } 11.172 11.173 + slot.put_into("title", ")") 11.174 + slot.select("actions", function() 11.175 + ui.link{ 11.176 + content = function() 11.177 + ui.image{ static = "icons/16/cancel.png" } 11.178 + slot.put(_"Cancel registration") 11.179 + end, 11.180 + module = "index", 11.181 + view = "index" 11.182 + } 11.183 + end) 11.184 + 11.185 end 11.186 } 11.187
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/app/main/index/reset_password.lua Sat Jan 02 12:00:00 2010 +0100 12.3 @@ -0,0 +1,81 @@ 12.4 +slot.put_into("title", _"Reset password") 12.5 + 12.6 +slot.select("actions", function() 12.7 + ui.link{ 12.8 + content = function() 12.9 + ui.image{ static = "icons/16/cancel.png" } 12.10 + slot.put(_"Cancel password reset") 12.11 + end, 12.12 + module = "index", 12.13 + view = "index" 12.14 + } 12.15 +end) 12.16 + 12.17 + 12.18 +local secret = param.get("secret") 12.19 + 12.20 +if not secret then 12.21 + ui.tag{ 12.22 + tag = 'p', 12.23 + content = _'Please enter your login name. You will receive an email with a link to reset your password.' 12.24 + } 12.25 + ui.form{ 12.26 + attr = { class = "vertical" }, 12.27 + module = "index", 12.28 + action = "reset_password", 12.29 + routing = { 12.30 + ok = { 12.31 + mode = "redirect", 12.32 + module = "index", 12.33 + view = "index" 12.34 + } 12.35 + }, 12.36 + content = function() 12.37 + ui.field.text{ 12.38 + label = "Login", 12.39 + name = "login" 12.40 + } 12.41 + ui.submit{ text = _"Request password reset link" } 12.42 + end 12.43 + } 12.44 + 12.45 +else 12.46 + 12.47 + ui.form{ 12.48 + attr = { class = "vertical" }, 12.49 + module = "index", 12.50 + action = "reset_password", 12.51 + routing = { 12.52 + ok = { 12.53 + mode = "redirect", 12.54 + module = "index", 12.55 + view = "index" 12.56 + } 12.57 + }, 12.58 + content = function() 12.59 + ui.tag{ 12.60 + tag = 'p', 12.61 + content = _'Please enter the email reset code you have received:' 12.62 + } 12.63 + ui.field.text{ 12.64 + label = _"Reset code", 12.65 + name = "secret", 12.66 + value = secret 12.67 + } 12.68 + ui.tag{ 12.69 + tag = 'p', 12.70 + content = _'Please enter your new password twice.' 12.71 + } 12.72 + ui.field.password{ 12.73 + label = "New password", 12.74 + name = "password1" 12.75 + } 12.76 + ui.field.password{ 12.77 + label = "New password (repeat)", 12.78 + name = "password2" 12.79 + } 12.80 + ui.submit{ text = _"Set new password" } 12.81 + end 12.82 + } 12.83 + 12.84 +end 12.85 \ No newline at end of file
13.1 --- a/app/main/initiative/_action/create.lua Fri Dec 25 12:00:00 2009 +0100 13.2 +++ b/app/main/initiative/_action/create.lua Sat Jan 02 12:00:00 2010 +0100 13.3 @@ -29,6 +29,15 @@ 13.4 area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec() 13.5 end 13.6 13.7 +local name = param.get("name") 13.8 + 13.9 +local name = util.trim(name) 13.10 + 13.11 +if #name < 3 then 13.12 + slot.put_into("error", _"This name is really too short!") 13.13 + return false 13.14 +end 13.15 + 13.16 local initiative = Initiative:new() 13.17 13.18 if not issue then 13.19 @@ -38,11 +47,9 @@ 13.20 issue:save() 13.21 end 13.22 13.23 - 13.24 - 13.25 initiative.issue_id = issue.id 13.26 - 13.27 -param.update(initiative, "name", "discussion_url") 13.28 +initiative.name = name 13.29 +param.update(initiative, "discussion_url") 13.30 initiative:save() 13.31 13.32 local draft = Draft:new()
14.1 --- a/app/main/initiative/show.lua Fri Dec 25 12:00:00 2009 +0100 14.2 +++ b/app/main/initiative/show.lua Sat Jan 02 12:00:00 2010 +0100 14.3 @@ -188,10 +188,19 @@ 14.4 end 14.5 14.6 14.7 -ui.tabs{ 14.8 +local current_draft_name = _"Current draft" 14.9 +if initiative.issue.half_frozen then 14.10 + current_draft_name = _"Voting proposal" 14.11 +end 14.12 + 14.13 +if initiative.issue.state == "finished" then 14.14 + current_draft_name = _"Voted proposal" 14.15 +end 14.16 + 14.17 +local tabs = { 14.18 { 14.19 name = "current_draft", 14.20 - label = _"Current draft", 14.21 + label = current_draft_name, 14.22 content = function() 14.23 if initiator then 14.24 ui.link{ 14.25 @@ -206,108 +215,136 @@ 14.26 end 14.27 execute.view{ module = "draft", view = "_show", params = { draft = initiative.current_draft } } 14.28 end 14.29 - }, 14.30 - { 14.31 - name = "suggestion", 14.32 - label = _"Suggestions", 14.33 - content = function() 14.34 - execute.view{ 14.35 - module = "suggestion", 14.36 - view = "_list", 14.37 - params = { 14.38 - initiative = initiative, 14.39 - suggestions_selector = initiative:get_reference_selector("suggestions") 14.40 - } 14.41 - } 14.42 - slot.put("<br />") 14.43 - if not initiative.issue.fully_frozen and not initiative.issue.closed then 14.44 - ui.link{ 14.45 - content = function() 14.46 - ui.image{ static = "icons/16/comment_add.png" } 14.47 - slot.put(_"Add new suggestion") 14.48 - end, 14.49 - attr = { onclick = "document.getElementById('add_suggestion_form').style.display='block';return(false)" }, 14.50 - static = "#" 14.51 - } 14.52 - end 14.53 - end 14.54 - }, 14.55 - { 14.56 - name = "satisfied_supporter", 14.57 - label = _"Supporter", 14.58 + } 14.59 +} 14.60 + 14.61 +if initiative.issue.ranks_available then 14.62 + tabs[#tabs+1] = { 14.63 + name = "voter", 14.64 + label = _"Voter", 14.65 content = function() 14.66 execute.view{ 14.67 module = "member", 14.68 view = "_list", 14.69 params = { 14.70 initiative = initiative, 14.71 - members_selector = initiative:get_reference_selector("supporting_members_snapshot") 14.72 - :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 14.73 - :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 14.74 - :add_field("direct_interest_snapshot.weight") 14.75 - :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 14.76 - :add_where("direct_supporter_snapshot.satisfied") 14.77 - } 14.78 - } 14.79 - end 14.80 - }, 14.81 - { 14.82 - name = "supporter", 14.83 - label = _"Potential supporter", 14.84 - content = function() 14.85 - execute.view{ 14.86 - module = "member", 14.87 - view = "_list", 14.88 - params = { 14.89 - initiative = initiative, 14.90 - members_selector = initiative:get_reference_selector("supporting_members_snapshot") 14.91 - :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 14.92 - :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 14.93 - :add_field("direct_interest_snapshot.weight") 14.94 - :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 14.95 - :add_where("NOT direct_supporter_snapshot.satisfied") 14.96 + members_selector = initiative.issue:get_reference_selector("direct_voters") 14.97 + :left_join("vote", nil, { "vote.initiative_id = ? AND vote.member_id = member.id", initiative.id }) 14.98 + :add_field("direct_voter.weight as voter_weight") 14.99 + :add_field("coalesce(vote.grade, 0) as grade") 14.100 } 14.101 } 14.102 end 14.103 - }, 14.104 - { 14.105 - name = "initiators", 14.106 - label = _"Initiators", 14.107 - content = function() 14.108 - execute.view{ module = "member", view = "_list", params = { members_selector = initiative:get_reference_selector("initiating_members") } } 14.109 - end 14.110 - }, 14.111 - { 14.112 - name = "drafts", 14.113 - label = _"Old drafts", 14.114 - content = function() 14.115 - execute.view{ module = "draft", view = "_list", params = { drafts = initiative.drafts } } 14.116 - end 14.117 - }, 14.118 - { 14.119 - name = "details", 14.120 - label = _"Details", 14.121 - content = function() 14.122 - ui.form{ 14.123 - attr = { class = "vertical" }, 14.124 - record = initiative, 14.125 - readonly = true, 14.126 + } 14.127 +end 14.128 + 14.129 +tabs[#tabs+1] = { 14.130 + name = "suggestion", 14.131 + label = _"Suggestions", 14.132 + content = function() 14.133 + execute.view{ 14.134 + module = "suggestion", 14.135 + view = "_list", 14.136 + params = { 14.137 + initiative = initiative, 14.138 + suggestions_selector = initiative:get_reference_selector("suggestions") 14.139 + } 14.140 + } 14.141 + slot.put("<br />") 14.142 + if not initiative.issue.fully_frozen and not initiative.issue.closed then 14.143 + ui.link{ 14.144 content = function() 14.145 - ui.field.text{ label = _"Issue policy", value = initiative.issue.policy.name } 14.146 - ui.field.text{ 14.147 - label = _"Created at", 14.148 - value = tostring(initiative.created) 14.149 - } 14.150 - ui.field.text{ 14.151 - label = _"Created at", 14.152 - value = format.timestamp(initiative.created) 14.153 - } 14.154 - ui.field.date{ label = _"Revoked at", name = "revoked" } 14.155 - ui.field.boolean{ label = _"Admitted", name = "admitted" } 14.156 - end 14.157 + ui.image{ static = "icons/16/comment_add.png" } 14.158 + slot.put(_"Add new suggestion") 14.159 + end, 14.160 + attr = { onclick = "document.getElementById('add_suggestion_form').style.display='block';return(false)" }, 14.161 + static = "#" 14.162 } 14.163 end 14.164 - }, 14.165 + end 14.166 +} 14.167 + 14.168 +tabs[#tabs+1] = { 14.169 + name = "satisfied_supporter", 14.170 + label = _"Supporter", 14.171 + content = function() 14.172 + execute.view{ 14.173 + module = "member", 14.174 + view = "_list", 14.175 + params = { 14.176 + initiative = initiative, 14.177 + members_selector = initiative:get_reference_selector("supporting_members_snapshot") 14.178 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 14.179 + :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 14.180 + :add_field("direct_interest_snapshot.weight") 14.181 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 14.182 + :add_where("direct_supporter_snapshot.satisfied") 14.183 + } 14.184 + } 14.185 + end 14.186 +} 14.187 + 14.188 +tabs[#tabs+1] = { 14.189 + name = "supporter", 14.190 + label = _"Potential supporter", 14.191 + content = function() 14.192 + execute.view{ 14.193 + module = "member", 14.194 + view = "_list", 14.195 + params = { 14.196 + initiative = initiative, 14.197 + members_selector = initiative:get_reference_selector("supporting_members_snapshot") 14.198 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 14.199 + :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 14.200 + :add_field("direct_interest_snapshot.weight") 14.201 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 14.202 + :add_where("NOT direct_supporter_snapshot.satisfied") 14.203 + } 14.204 + } 14.205 + end 14.206 +} 14.207 + 14.208 +tabs[#tabs+1] = { 14.209 + name = "initiators", 14.210 + label = _"Initiators", 14.211 + content = function() 14.212 + execute.view{ module = "member", view = "_list", params = { members_selector = initiative:get_reference_selector("initiating_members") } } 14.213 + end 14.214 +} 14.215 + 14.216 +tabs[#tabs+1] = { 14.217 + name = "drafts", 14.218 + label = _"Old drafts", 14.219 + content = function() 14.220 + execute.view{ module = "draft", view = "_list", params = { drafts = initiative.drafts } } 14.221 + end 14.222 +} 14.223 + 14.224 +tabs[#tabs+1] = { 14.225 + name = "details", 14.226 + label = _"Details", 14.227 + content = function() 14.228 + ui.form{ 14.229 + attr = { class = "vertical" }, 14.230 + record = initiative, 14.231 + readonly = true, 14.232 + content = function() 14.233 + ui.field.text{ label = _"Issue policy", value = initiative.issue.policy.name } 14.234 + ui.field.text{ 14.235 + label = _"Created at", 14.236 + value = tostring(initiative.created) 14.237 + } 14.238 + ui.field.text{ 14.239 + label = _"Created at", 14.240 + value = format.timestamp(initiative.created) 14.241 + } 14.242 + ui.field.date{ label = _"Revoked at", name = "revoked" } 14.243 + ui.field.boolean{ label = _"Admitted", name = "admitted" } 14.244 + end 14.245 + } 14.246 + end 14.247 } 14.248 14.249 14.250 +ui.tabs(tabs) 14.251 +
15.1 --- a/app/main/issue/_list.lua Fri Dec 25 12:00:00 2009 +0100 15.2 +++ b/app/main/issue/_list.lua Sat Jan 02 12:00:00 2010 +0100 15.3 @@ -11,9 +11,13 @@ 15.4 filters = { 15.5 { 15.6 type = "boolean", 15.7 - name = "any", 15.8 - label = _"Any", 15.9 - selector_modifier = function() end 15.10 + name = "open", 15.11 + label = _"Open", 15.12 + selector_modifier = function(selector, value) 15.13 + if value then 15.14 + selector:add_where("issue.closed ISNULL") 15.15 + end 15.16 + end 15.17 }, 15.18 { 15.19 type = "boolean", 15.20 @@ -150,14 +154,14 @@ 15.21 name = "max_potential_support", 15.22 label = _"Max potential support", 15.23 selector_modifier = function(selector) 15.24 - selector:add_order_by("(SELECT max(supporter_count) FROM initiative WHERE initiative.issue_id = issue.id)") 15.25 + selector:add_order_by("(SELECT max(supporter_count) FROM initiative WHERE initiative.issue_id = issue.id) DESC") 15.26 end 15.27 }, 15.28 { 15.29 name = "max_support", 15.30 label = _"Max support", 15.31 selector_modifier = function(selector) 15.32 - selector:add_order_by("(SELECT max(satisfied_supporter_count) FROM initiative WHERE initiative.issue_id = issue.id)") 15.33 + selector:add_order_by("(SELECT max(satisfied_supporter_count) FROM initiative WHERE initiative.issue_id = issue.id) DESC") 15.34 end 15.35 }, 15.36 { 15.37 @@ -214,7 +218,16 @@ 15.38 { 15.39 label = _"State", 15.40 content = function(record) 15.41 - ui.field.issue_state{ value = record.state } 15.42 + if record.state == "voting" then 15.43 + ui.link{ 15.44 + content = _"Voting", 15.45 + module = "vote", 15.46 + view = "list", 15.47 + params = { issue_id = record.id } 15.48 + } 15.49 + else 15.50 + ui.field.issue_state{ value = record.state } 15.51 + end 15.52 end 15.53 }, 15.54 {
16.1 --- a/app/main/issue/_show_head.lua Fri Dec 25 12:00:00 2009 +0100 16.2 +++ b/app/main/issue/_show_head.lua Sat Jan 02 12:00:00 2010 +0100 16.3 @@ -85,3 +85,24 @@ 16.4 } 16.5 16.6 -- ui.twitter("http://example.com/t" .. tostring(issue.id)) 16.7 + 16.8 + 16.9 +if issue.state == 'voting' then 16.10 + ui.container{ 16.11 + attr = { class = "voting_active_info" }, 16.12 + content = function() 16.13 + slot.put(_"Voting for this issue is currently running!") 16.14 + slot.put(" ") 16.15 + ui.link{ 16.16 + content = function() 16.17 + slot.put(_"Vote now") 16.18 + end, 16.19 + module = "vote", 16.20 + view = "list", 16.21 + params = { issue_id = issue.id } 16.22 + } 16.23 + end 16.24 + } 16.25 + slot.put("<br />") 16.26 +end 16.27 +
17.1 --- a/app/main/member/_show_thumb.lua Fri Dec 25 12:00:00 2009 +0100 17.2 +++ b/app/main/member/_show_thumb.lua Sat Jan 02 12:00:00 2010 +0100 17.3 @@ -17,16 +17,27 @@ 17.4 ui.container{ 17.5 attr = { class = "flags" }, 17.6 content = function() 17.7 - if (issue or initiative) and member.weight > 1 then 17.8 + local weight = 0 17.9 + if member.weight then 17.10 + weight = member.weight 17.11 + end 17.12 + if member.voter_weight then 17.13 + weight = member.voter_weight 17.14 + end 17.15 + if (issue or initiative) and weight > 1 then 17.16 local module 17.17 if issue then 17.18 module = "interest" 17.19 elseif initiative then 17.20 - module = "supporter" 17.21 + if member.voter_weight then 17.22 + module = "vote" 17.23 + else 17.24 + module = "supporter" 17.25 + end 17.26 end 17.27 ui.link{ 17.28 attr = { title = _"Number of incoming delegations, follow link to see more details" }, 17.29 - content = _("+ #{weight}", { weight = member.weight - 1 }), 17.30 + content = _("+ #{weight}", { weight = weight - 1 }), 17.31 module = module, 17.32 view = "show_incoming", 17.33 params = { 17.34 @@ -35,6 +46,39 @@ 17.35 issue_id = issue and issue.id or nil 17.36 } 17.37 } 17.38 + else 17.39 + slot.put(" ") 17.40 + end 17.41 + if member.grade then 17.42 + ui.container{ 17.43 + content = function() 17.44 + if member.grade > 0 then 17.45 + ui.image{ 17.46 + attr = { 17.47 + alt = _"Voted yes", 17.48 + title = _"Voted yes" 17.49 + }, 17.50 + static = "icons/16/thumb_up_green.png" 17.51 + } 17.52 + elseif member.grade < 0 then 17.53 + ui.image{ 17.54 + attr = { 17.55 + alt = _"Voted no", 17.56 + title = _"Voted no" 17.57 + }, 17.58 + static = "icons/16/thumb_down_red.png" 17.59 + } 17.60 + else 17.61 + ui.image{ 17.62 + attr = { 17.63 + alt = _"Abstention", 17.64 + title = _"Abstention" 17.65 + }, 17.66 + static = "icons/16/bullet_yellow.png" 17.67 + } 17.68 + end 17.69 + end 17.70 + } 17.71 end 17.72 if member.admin then 17.73 ui.image{
18.1 --- a/app/main/member/edit.lua Fri Dec 25 12:00:00 2009 +0100 18.2 +++ b/app/main/member/edit.lua Sat Jan 02 12:00:00 2010 +0100 18.3 @@ -29,7 +29,7 @@ 18.4 ui.field.text{ label = _"Organizational unit", name = "organizational_unit" } 18.5 ui.field.text{ label = _"Internal posts", name = "internal_posts" } 18.6 ui.field.text{ label = _"Real name", name = "realname" } 18.7 - ui.field.text{ label = _"Birthday", name = "birthday" } 18.8 + ui.field.text{ label = _"Birthday" .. " YYYY-MM-DD ", name = "birthday" } 18.9 ui.field.text{ label = _"Address", name = "address", multiline = true } 18.10 ui.field.text{ label = _"email", name = "email" } 18.11 ui.field.text{ label = _"xmpp", name = "xmpp_address" }
19.1 --- a/app/main/opinion/_action/update.lua Fri Dec 25 12:00:00 2009 +0100 19.2 +++ b/app/main/opinion/_action/update.lua Sat Jan 02 12:00:00 2010 +0100 19.3 @@ -4,8 +4,15 @@ 19.4 19.5 local opinion = Opinion:by_pk(member_id, suggestion_id) 19.6 19.7 +local suggestion = Suggestion:by_id(suggestion_id) 19.8 + 19.9 +if not suggestion then 19.10 + slot.put_into("error", _"This suggestion has been meanwhile deleted") 19.11 + return false 19.12 +end 19.13 + 19.14 -- TODO important m1 selectors returning result _SET_! 19.15 -local issue = opinion.initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 19.16 +local issue = suggestion.initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 19.17 19.18 if issue.closed then 19.19 slot.put_into("error", _"This issue is already closed.")
20.1 --- a/app/main/opinion/_list.lua Fri Dec 25 12:00:00 2009 +0100 20.2 +++ b/app/main/opinion/_list.lua Sat Jan 02 12:00:00 2010 +0100 20.3 @@ -4,20 +4,32 @@ 20.4 records = opinions_selector:exec(), 20.5 columns = { 20.6 { 20.7 - label = _"Member login", 20.8 - name = "member_login" 20.9 - }, 20.10 - { 20.11 label = _"Member name", 20.12 name = "member_name" 20.13 }, 20.14 { 20.15 label = _"Degree", 20.16 - name = "degree" 20.17 + content = function(record) 20.18 + if record.degree == -2 then 20.19 + slot.put(_"must not") 20.20 + elseif record.degree == -1 then 20.21 + slot.put(_"should not") 20.22 + elseif record.degree == 1 then 20.23 + slot.put(_"should") 20.24 + elseif record.degree == 2 then 20.25 + slot.put(_"must") 20.26 + end 20.27 + end 20.28 }, 20.29 { 20.30 - label = _"Fulfilled", 20.31 - name = "fulfilled" 20.32 + label = _"Suggestion currently implemented", 20.33 + content = function(record) 20.34 + if record.fulfilled then 20.35 + slot.put(_"Yes") 20.36 + else 20.37 + slot.put(_"No") 20.38 + end 20.39 + end 20.40 }, 20.41 } 20.42 } 20.43 \ No newline at end of file
21.1 --- a/app/main/suggestion/_action/add.lua Fri Dec 25 12:00:00 2009 +0100 21.2 +++ b/app/main/suggestion/_action/add.lua Sat Jan 02 12:00:00 2010 +0100 21.3 @@ -4,10 +4,19 @@ 21.4 return false 21.5 end 21.6 21.7 +local name = param.get("name") 21.8 +local name = util.trim(name) 21.9 + 21.10 +if #name < 3 then 21.11 + slot.put_into("error", _"This title is really too short!") 21.12 + return false 21.13 +end 21.14 + 21.15 local suggestion = Suggestion:new() 21.16 21.17 suggestion.author_id = app.session.member.id 21.18 -param.update(suggestion, "name", "description", "initiative_id") 21.19 +suggestion.name = name 21.20 +param.update(suggestion, "description", "initiative_id") 21.21 suggestion:save() 21.22 21.23 -- TODO important m1 selectors returning result _SET_!
22.1 --- a/app/main/suggestion/show.lua Fri Dec 25 12:00:00 2009 +0100 22.2 +++ b/app/main/suggestion/show.lua Sat Jan 02 12:00:00 2010 +0100 22.3 @@ -2,6 +2,19 @@ 22.4 22.5 slot.put_into("title", encode.html(_"Suggestion for initiative: '#{name}'":gsub("#{name}", suggestion.initiative.name) )) 22.6 22.7 +slot.select("actions", function() 22.8 + ui.link{ 22.9 + content = function() 22.10 + ui.image{ static = "icons/16/resultset_previous.png" } 22.11 + slot.put(_"Back") 22.12 + end, 22.13 + module = "initiative", 22.14 + view = "show", 22.15 + id = suggestion.initiative.id, 22.16 + params = { tab = "suggestion" } 22.17 + } 22.18 +end) 22.19 + 22.20 ui.form{ 22.21 attr = { class = "vertical" }, 22.22 record = suggestion,
23.1 --- a/app/main/vote/list.lua Fri Dec 25 12:00:00 2009 +0100 23.2 +++ b/app/main/vote/list.lua Sat Jan 02 12:00:00 2010 +0100 23.3 @@ -109,13 +109,46 @@ 23.4 id = "entry_" .. tostring(initiative.id) 23.5 }, 23.6 content = function() 23.7 - ui.link{ 23.8 - attr = { class = "clickable" }, 23.9 - content = initiative.name, 23.10 - module = "initiative", 23.11 - view = "show", 23.12 - id = initiative.id 23.13 + local initiators = initiative.initiating_members 23.14 + local initiator_names = {} 23.15 + for i, initiator in ipairs(initiators) do 23.16 + initiator_names[#initiator_names+1] = initiator.name 23.17 + end 23.18 + local initiator_names_string = table.concat(initiator_names, ", ") 23.19 + ui.container{ 23.20 + attr = { style = "float: right;" }, 23.21 + content = function() 23.22 + ui.link{ 23.23 + attr = { class = "clickable" }, 23.24 + content = _"Show", 23.25 + module = "initiative", 23.26 + view = "show", 23.27 + id = initiative.id 23.28 + } 23.29 + slot.put(" ") 23.30 + ui.link{ 23.31 + attr = { class = "clickable", target = "_blank" }, 23.32 + content = _"(new window)", 23.33 + module = "initiative", 23.34 + view = "show", 23.35 + id = initiative.id 23.36 + } 23.37 + slot.put(" ") 23.38 + ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" } 23.39 + end 23.40 } 23.41 + slot.put(encode.html(initiative.shortened_name)) 23.42 + if #initiators > 1 then 23.43 + ui.container{ 23.44 + attr = { style = "font-size: 80%;" }, 23.45 + content = _"Initiators" .. ": " .. initiator_names_string 23.46 + } 23.47 + else 23.48 + ui.container{ 23.49 + attr = { style = "font-size: 80%;" }, 23.50 + content = _"Initiator" .. ": " .. initiator_names_string 23.51 + } 23.52 + end 23.53 end 23.54 } 23.55 end
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/app/main/vote/show_incoming.lua Sat Jan 02 12:00:00 2010 +0100 24.3 @@ -0,0 +1,19 @@ 24.4 +local initiative = Initiative:by_id(param.get("initiative_id", atom.integer)) 24.5 +local issue = initiative.issue 24.6 +local member = Member:by_id(param.get("member_id", atom.integer)) 24.7 + 24.8 +local members_selector = Member:new_selector() 24.9 + :join("delegating_voter", nil, "delegating_voter.member_id = member.id") 24.10 + :add_where{ "delegating_voter.issue_id = ?", issue.id } 24.11 + :add_where{ "delegating_voter.delegate_member_ids[1] = ?", member.id } 24.12 + :add_field{ "delegating_voter.weight" } 24.13 + 24.14 +execute.view{ 24.15 + module = "member", 24.16 + view = "_list", 24.17 + params = { 24.18 + members_selector = members_selector, 24.19 + issue = issue, 24.20 + trustee = member 24.21 + } 24.22 +} 24.23 \ No newline at end of file
25.1 --- a/config/default.lua Fri Dec 25 12:00:00 2009 +0100 25.2 +++ b/config/default.lua Sat Jan 02 12:00:00 2010 +0100 25.3 @@ -1,5 +1,5 @@ 25.4 config.app_name = "LiquidFeedback" 25.5 -config.app_version = "beta1" 25.6 +config.app_version = "beta2" 25.7 25.8 config.app_title = config.app_name .. " (" .. request.get_config_name() .. " environment)" 25.9 25.10 @@ -7,6 +7,8 @@ 25.11 25.12 config.app_service_provider = "Snake Oil<br/>10000 Berlin<br/>Germany" 25.13 25.14 +config.use_terms = "=== Nutzungsbedingungen ===\nAlles ist verboten" 25.15 + 25.16 config.member_image_convert_func = { 25.17 avatar = function(data) return os.pfilter(data, "convert", "jpeg:-", "-thumbnail", "48x48", "jpeg:-") end, 25.18 photo = function(data) return os.pfilter(data, "convert", "jpeg:-", "-thumbnail", "240x240", "jpeg:-") end 25.19 @@ -17,8 +19,13 @@ 25.20 photo = nil 25.21 } 25.22 25.23 +config.mail_subject_prefix = "[LiquidFeedback] " 25.24 + 25.25 config.fastpath_url_func = nil 25.26 25.27 +config.download_dir = nil 25.28 + 25.29 +config.download_use_terms = "=== Nutzungsbedingungen ===\nAlles ist verboten" 25.30 25.31 -- uncomment the following two lines to use C implementations of chosen 25.32 -- functions and to disable garbage collection during the request, to 25.33 @@ -45,10 +52,7 @@ 25.34 end 25.35 end 25.36 25.37 --- 'request.get_relative_baseurl()' should be replaced by the absolute 25.38 --- base URL of the application, as otherwise HTTP redirects will not be 25.39 --- standard compliant 25.40 -request.set_absolute_baseurl(request.get_relative_baseurl()) 25.41 +request.set_absolute_baseurl(config.absolute_base_url) 25.42 25.43 25.44
26.1 --- a/config/development.lua Fri Dec 25 12:00:00 2009 +0100 26.2 +++ b/config/development.lua Sat Jan 02 12:00:00 2010 +0100 26.3 @@ -1,6 +1,11 @@ 26.4 +config.absolute_base_url = "http://10.8.33.34/lf/" 26.5 + 26.6 execute.config("default") 26.7 26.8 config.formatting_engine_executeables = { 26.9 rocketwiki= "/opt/rocketwiki/rocketwiki-lqfb", 26.10 compat = "/opt/rocketwiki/rocketwiki-lqfb-compat" 26.11 } 26.12 + 26.13 +config.mail_from = "LiquidFeedback" 26.14 +config.mail_reply_to = "liquid-support@localhost"
27.1 --- a/config/testing.lua Fri Dec 25 12:00:00 2009 +0100 27.2 +++ b/config/testing.lua Sat Jan 02 12:00:00 2010 +0100 27.3 @@ -1,3 +1,5 @@ 27.4 +config.absolute_base_url = "http://www.public-software-group.org/liquid_feedback_testing/" 27.5 + 27.6 execute.config("default") 27.7 27.8 config.formatting_engine_executeables = {
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/env/util/trim.lua Sat Jan 02 12:00:00 2010 +0100 28.3 @@ -0,0 +1,3 @@ 28.4 +function util.trim(string) 28.5 + return (string:gsub("^%s*", ""):gsub("%s*$", "")) 28.6 +end 28.7 \ No newline at end of file
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/locale/help/index.download.de.txt Sat Jan 02 12:00:00 2010 +0100 29.3 @@ -0,0 +1,2 @@ 29.4 +=Download der Datenbank= 29.5 +Im Interesse der Nachvollziehbarkeit ist es jedem Mitglied möglich, eine Kopie der gesamten Datenbank herunterzuladen. Hierbei werden jedoch aus Sicherheits- und Datenschutzgründen bestimmte Informationen (z. B. Passwörter und E-Mail-Adressen) entfernt. Das Dateiformat ist gzip-komprimiertes SQL für die Datenbank PostgreSQL.
30.1 --- a/locale/help/initiative.show.de.txt Fri Dec 25 12:00:00 2009 +0100 30.2 +++ b/locale/help/initiative.show.de.txt Sat Jan 02 12:00:00 2010 +0100 30.3 @@ -5,6 +5,6 @@ 30.4 =überarbeiteter Entwurf, Umsetzungsvermerk= 30.5 Anhand der (klassifizierten und quantifizierten) Anregungen entscheiden die Initiatoren, was sie in einem neuen Entwurf besser dargestellen, ergänzen oder ändern. Der geänderte Entwurf wird den Unterstützern zur Bestätigung vorgelegt. Unterstützer können Anregungen als umgesetzt markieren, wenn die Anregung aus ihrer Sicht (hinreichend) umgesetzt wurde. Die einzelnen Unterstützer können diese Frage durchaus unterschiedlich beurteilen. 30.6 =wenn du nicht gehört wirst= 30.7 -Wenn die Initiatoren deine Anregungen aus für dich nicht nachvollziehbaren Gründen nicht berücksichtigen, kannst du natürlich deine Änderungen in einer eigenen Initiative zur Diskussion stellen. 30.8 +Wenn die Initiatoren deine Anregungen aus für dich nicht nachvollziehbaren Gründen nicht berücksichtigen, kannst du natürlich jederzeit eine eigene Initiative starten. 30.9 =wenn du diese Initiative ablehnst= 30.10 Wenn du diese Initiative grundsätzlich ablehnst, solltest du auf dieser Seite gar nichts machen, sondern die Initiative(n), der/denen du positiv gegenüber stehst, unterstützen und/oder deine eigene Initiative zu diesem Thema starten.
31.1 --- a/locale/translations.de.lua Fri Dec 25 12:00:00 2009 +0100 31.2 +++ b/locale/translations.de.lua Sat Jan 02 12:00:00 2010 +0100 31.3 @@ -5,6 +5,7 @@ 31.4 ["#{number} Image(s) has been deleted"] = "Es wurde(n) #{number} Bild(er) gelöscht"; 31.5 ["#{number} Image(s) has been updated"] = "Es wurde(n) #{number} Bild(er) aktualisiert"; 31.6 ["(change URL)"] = "(URL ändern)"; 31.7 +["(new window)"] = "(neues Fenster)"; 31.8 ["+ #{weight}"] = "+ #{weight}"; 31.9 ["A-Z"] = "A-Z"; 31.10 ["About"] = "About"; 31.11 @@ -35,10 +36,14 @@ 31.12 ["Autoreject is off."] = "Auto-Ablehnen ist aus"; 31.13 ["Autoreject is on."] = "Auto-Ablehnen ist an"; 31.14 ["Avatar"] = "Avatar"; 31.15 +["Back"] = "Zurück"; 31.16 ["Become a member"] = "Mitglied werden"; 31.17 ["Birthday"] = "Geburtstag"; 31.18 ["Bug report"] = "Fehlerbericht"; 31.19 +["Can't send confirmation email"] = "Bestätigungs-E-Mail kann nicht versendet werden."; 31.20 ["Cancel"] = "Abbrechen"; 31.21 +["Cancel password reset"] = "Kennwort-Rücksetzung abbrechen"; 31.22 +["Cancel registration"] = "Registration abbrechen"; 31.23 ["Cancelled"] = "Abgebrochen"; 31.24 ["Change area delegation"] = "Delegation für Themengebiet ändern"; 31.25 ["Change global delegation"] = "Globale Delegation ändern"; 31.26 @@ -50,6 +55,9 @@ 31.27 ["Collective opinion"] = "Meinungsbild"; 31.28 ["Commit suggestion"] = "Anregung speichern"; 31.29 ["Compare"] = "Vergleichen"; 31.30 +["Confirm"] = "Bestätigen"; 31.31 +["Confirmation code"] = "Bestätigungscode"; 31.32 +["Confirmation code invalid!"] = "Bestätigungscode ist ungültig!"; 31.33 ["Contacts"] = "Kontakte"; 31.34 ["Content"] = "Inhalt"; 31.35 ["Counting of votes"] = "Auszählung"; 31.36 @@ -75,6 +83,11 @@ 31.37 ["Edit initiative"] = "Initiative bearbeiten"; 31.38 ["Edit my page"] = "Meine Seite bearbeiten"; 31.39 ["Edit my profile"] = "Mein Profil bearbeiten"; 31.40 +["Email address"] = "E-Mail-Adresse"; 31.41 +["Email address confirmation"] = "Bestätigung der E-Mail-Adresse"; 31.42 +["Email address is confirmed now"] = "E-Mail-Adresse ist jetzt bestätigt"; 31.43 +["Email address too short!"] = "E-Mail-Adresse ist zu kurz!"; 31.44 +["Email confirmation request"] = "Bestätigung Deiner E-Mail-Adresse"; 31.45 ["Empty help text: #{id}.#{lang}.txt"] = "Leerer Hilfe-Text: #{id}.#{lang}.txt"; 31.46 ["Error while updating member, database reported:<br /><br /> (#{errormessage})"] = "Fehler beim aktualisieren des Mitglieds, die Datenbank berichtet folgenden Fehler:<br /><br /> (#{errormessage})"; 31.47 ["External memberships"] = "Externe Mitgliedschaften"; 31.48 @@ -88,12 +101,15 @@ 31.49 ["Global delegation"] = "Globale Delegation"; 31.50 ["Global delegation active"] = "Globale Delegation aktiv"; 31.51 ["Half frozen at"] = "Halb eingefroren am/um"; 31.52 +["Hello "] = "Hallo "; 31.53 ["Help for: #{text}"] = "Hilfe zu: #{text}"; 31.54 ["Hide"] = "Verstecken"; 31.55 ["Hide this help message"] = "Diesen Hilfetext ausblenden"; 31.56 ["Home"] = "Startseite"; 31.57 +["I accept the terms of use by checking the following checkbox:"] = "Ich akzeptiere die Nutzungsbedingungen durch Auswahl der folgenden Ankreuzbox:"; 31.58 ["Id"] = "Id"; 31.59 ["Ident number"] = "Ident-Nummer"; 31.60 +["If this link is not working, please open following url in your web browser:\n\n"] = "Sollte der Link nicht funktionieren, öffne bitte die folgenden URL in Deinem Web-Browser:\n\n"; 31.61 ["Images"] = "Bilder"; 31.62 ["In discussion"] = "In Diskussion"; 31.63 ["Incoming delegations"] = "Eingehende Delegationen"; 31.64 @@ -103,6 +119,7 @@ 31.65 ["Initiative successfully updated"] = "Initiative erfolgreich aktualisiert"; 31.66 ["Initiative: '#{name}'"] = "Initiative: '#{name}'"; 31.67 ["Initiatives"] = "Initiativen"; 31.68 +["Initiator"] = "Initiator"; 31.69 ["Initiators"] = "Initiatoren"; 31.70 ["Interest not existant"] = "Interesse existiert nicht"; 31.71 ["Interest removed"] = "Interesse entfernt"; 31.72 @@ -112,7 +129,6 @@ 31.73 ["Internal posts"] = "Interne Ämter"; 31.74 ["Invalid username or password!"] = "Ungültiger Benutzername oder Kennwort"; 31.75 ["Invite code"] = "Invite-Code"; 31.76 -["Invite code valid!"] = "Invite-Code gültig!"; 31.77 ["Issue"] = "Thema"; 31.78 ["Issue ##{id}"] = "Issue ##{id}"; 31.79 ["Issue ##{id} (#{policy_name})"] = "Thema ##{id} (#{policy_name})"; 31.80 @@ -127,7 +143,6 @@ 31.81 ["License"] = "Lizenz"; 31.82 ["Locked?"] = "Gesperrt?"; 31.83 ["Login"] = "Anmeldung"; 31.84 -["Login is available"] = "Anmeldename ist verfügbar"; 31.85 ["Login name"] = "Anmeldename"; 31.86 ["Login successful!"] = "Anmeldung erfolgreich"; 31.87 ["Logout"] = "Abmelden"; 31.88 @@ -159,7 +174,6 @@ 31.89 ["Mobile phone"] = "Mobiltelefon"; 31.90 ["My opinion"] = "Meine Meinung"; 31.91 ["Name"] = "Name"; 31.92 -["Name is available"] = "Name ist verfügbar"; 31.93 ["New"] = "Neu"; 31.94 ["New draft has been added to initiative"] = "Neuer Entwurf wurde der Initiative hinzugefügt"; 31.95 ["New draft revision"] = "Neue Revision des Entwurfs"; 31.96 @@ -182,13 +196,19 @@ 31.97 ["Old password"] = "Altes Kennwort"; 31.98 ["Old password is wrong"] = "Das alte Kennwort ist falsch"; 31.99 ["Oldest"] = "Älteste"; 31.100 +["On that page please enter the confirmation code:\n\n"] = "Auf dieser Seite gebe bitte folgenden Bestätigungscode ein:\n\n"; 31.101 +["On that page please enter the reset code:\n\n"] = "Auf dieser Seite gebe bitte den folgenden Rücksetzcode ein:\n\n"; 31.102 ["One issue"] = "Ein Thema"; 31.103 ["One issue you are interested in"] = "Ein Thema, das Dich interessiert"; 31.104 +["One step back"] = "Ein Schritt zurück"; 31.105 +["Open"] = "Offen"; 31.106 ["Order by"] = "Sortieren nach"; 31.107 ["Organizational unit"] = "Organisationseinheit"; 31.108 ["Outgoing delegations"] = "Ausgehende Delegationen"; 31.109 ["Password"] = "Kennwort"; 31.110 ["Password (repeat)"] = "Kennwort (wiederholen)"; 31.111 +["Password has been reset successfully"] = "Kennwort wurde erfolgreich zurückgesetzt"; 31.112 +["Password reset request"] = "Kennwort-Rücksetzung anfordern"; 31.113 ["Passwords don't match!"] = "Kennwörter stimmen nicht überein!"; 31.114 ["Passwords must consist of at least 8 characters!"] = "Das Kennwort muß zumindest 8 Zeichen lang sein!"; 31.115 ["Phone"] = "Telefon"; 31.116 @@ -196,7 +216,12 @@ 31.117 ["Please choose a login name. This name will not be shown to others and is used only by you to login into the system. The login name is case sensitive."] = "Bitte wähle einen Anmeldenamen. Dieser wird anderen nicht gezeigt und nur von Dir zum Anmelden verwendet. Groß- und Kleinschreibung wird berücksichtigt."; 31.118 ["Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you. You CAN'T change this name later, so please choose it wisely!"] = "Bitte wähle einen Namen, z. B. Deinen Real- oder Nicknamen. Dieser wird anderen angezeigt um Dich zu identifizieren. Du kannst Deinen Namen später NICHT ändern, wähle ihn also weise!"; 31.119 ["Please choose a password and enter it twice. The password is case sensitive."] = "Bitte wähle ein Kennwort und gebe es zweimal ein. Groß- und Kleinschreibung wird berücksichtigt."; 31.120 +["Please confirm your email address by clicking the following link:\n\n"] = "Bitte bestätige Deine E-Mail-Adresse, indem Du den folgenden Link anklickst:\n\n"; 31.121 +["Please enter the email reset code you have received:"] = "Bitte gib den Rücksetzcode ein, den Du erhalten hast:"; 31.122 ["Please enter the invite code you've received."] = "Bitte gib den Invite-Code ein, den Du erhalten hast."; 31.123 +["Please enter your email address. This address will be used for automatic notifications (if you request them) and in case you've lost your password. This address will not be published. After registration you will receive an email with a confirmation link."] = "Bitte gib Deine E-Mail-Adresse ein. Diese Adresse wird für automatische Benachrichtigungen (wenn Du diese anforderst) sowie zum Zurücksetzen des Kennworts verwendet. Diese Adresse wird nicht veröffentlicht. Nach Abschluß der Registration wirst Du eine E-Mail mit einem Link zum Bestätigen der Adresse erhalten."; 31.124 +["Please enter your login name. You will receive an email with a link to reset your password."] = "Bitte gib Deinen Anmeldenamen ein. Du wirst eine E-Mail mit einem Link zum Zurücksetzen des Kennworts erhalten."; 31.125 +["Please enter your new password twice."] = "Bitte gib Dein neues Kennwort zweimal ein:"; 31.126 ["Policy"] = "Regelwerk"; 31.127 ["Population"] = "Grundgesamtheit"; 31.128 ["Posts"] = "Ämter"; 31.129 @@ -220,6 +245,11 @@ 31.130 ["Remove my membership"] = "Mitgliedschaft aufgeben"; 31.131 ["Remove my support from this initiative"] = "Meine Unterstützung der Initiative entziehen"; 31.132 ["Repeat new password"] = "Neues Kennwort wiederholen"; 31.133 +["Request password reset link"] = "Link zum Rücksetzen des Kennworts anfordern"; 31.134 +["Reset code"] = "Rücksetzcode"; 31.135 +["Reset code is invalid!"] = "Rücksetzcode ist ungültig"; 31.136 +["Reset link has been send for this member"] = "Rücksetz-Link wurde versendet"; 31.137 +["Reset password"] = "Kennwort zurücksetzen"; 31.138 ["Revoke"] = "Widerrufen"; 31.139 ["Revoked at"] = "Zurückgezogen am/um"; 31.140 ["Save"] = "Speichern"; 31.141 @@ -235,6 +265,7 @@ 31.142 ["Set delegation for Issue ##{number} in Area '#{area_name}'"] = "Delegation für Thema ##{number} im Themenbereich '#{area_name}' festlegen"; 31.143 ["Set global delegation"] = "Globale Delegation festlegen"; 31.144 ["Set issue delegation"] = "Delegation für Thema festlegen"; 31.145 +["Set new password"] = "Neues Kennwort setzen"; 31.146 ["Show"] = "Zeige"; 31.147 ["Show active members"] = "Zeige aktive Mitglieder"; 31.148 ["Show all initiatives"] = "Zeige alle Initiativen"; 31.149 @@ -245,10 +276,16 @@ 31.150 ["Show member"] = "Mitglied anzeigen"; 31.151 ["Software"] = "Software"; 31.152 ["Some JavaScript based functions (voting in particular) will not work.\nFor this beta, please use a current version of Firefox, Safari, Opera(?), Konqueror or another (more) standard compliant browser.\nAlternative access without JavaScript will be available soon."] = "Einige auf JavaScript basierende Funktionen (insbesondere der Abstimmung) sind nicht benutzbar.\nFür diese Beta verwende bitte eine aktuelle Version von Firefox, Safari, Opera(?), Konqueror oder einen anderen (mehr) den Standards entsprechenden Browser.\nEin alternativer Zugriff ohne JavaScript wird bald zur Verfügung stehen."; 31.153 +["Sorry, but there is not confirmed email address for your account. Please contact the administrator or support."] = "Sorry, aber für diesen Account ist keine bestätigte E-Mail-Adresse hinterlegt. Bitte wende Dich an den Administrator oder den Support."; 31.154 ["Sorry, you have reached your personal flood limit. Please be slower..."] = "Sorry, Du hast Dein persönliches Flood-Limit erreicht. Bitte sei langsamer..."; 31.155 ["Sorry, your contingent for creating initiatives has been used up. Please try again later."] = "Sorry, Dein Antragskontingent ist zur Zeit ausgeschöpft. Bitte versuche es später erneut!"; 31.156 ["State"] = "Zustand"; 31.157 ["Statement"] = "Statement"; 31.158 +["Step 1/5: Invite code"] = "Schritt 1/5: Invite-Code"; 31.159 +["Step 2/5: Email address"] = "Schritt 2/5: E-Mail-Adresse"; 31.160 +["Step 3/5: Username"] = "Schritt 3/5: Benutzername"; 31.161 +["Step 4/5: Login name"] = "Schritt 4/5: Anmeldename"; 31.162 +["Step 5/5: Terms of use and password"] = "Schritt 5/5: Nutzungsbedingungen und Kennwort"; 31.163 ["Suggestion"] = "Anregung"; 31.164 ["Suggestion currently implemented"] = "Anregung zur Zeit umgesetzt"; 31.165 ["Suggestion currently not implemented"] = "Anregung zur Zeit nicht umgesetzt"; 31.166 @@ -258,13 +295,19 @@ 31.167 ["Support this initiative"] = "Diese Initiative unterstützen"; 31.168 ["Supported initiatives"] = "Unterstützte Initiativen"; 31.169 ["Supporter"] = "Unterstützer"; 31.170 +["Terms accepted"] = "Bedingungen akzeptiert"; 31.171 ["That's me!"] = "Das bin ich"; 31.172 ["The code you've entered is invalid"] = "Den Code den Du eingeben hast ist nicht gültig!"; 31.173 ["The drafts do not differ"] = "Die Entwürfe unterscheiden sich nicht"; 31.174 ["This issue is already closed."] = "Das Thema ist schon geschlossen."; 31.175 ["This issue is already frozen."] = "Das Thema ist schon eingefroren"; 31.176 ["This login is already taken, please choose another one!"] = "Dieser Anmeldename ist bereits vergeben, bitte wähle einen anderen!"; 31.177 +["This login is too short!"] = "Dieser Anmeldename ist zu kurz!"; 31.178 ["This name is already taken, please choose another one!"] = "Dieser Name ist bereits vergeben, bitte wähle einen anderen!"; 31.179 +["This name is really too short!"] = "Dieser Name ist wirklich zu kurz!"; 31.180 +["This suggestion has been meanwhile deleted"] = "Diese Anregung wurde zwischenzeitlich gelöscht"; 31.181 +["This title is really too short!"] = "Dieser Titel ist wirklich zu kurz!"; 31.182 +["This username is too short!"] = "Dieser Benutzername ist zu kurz!"; 31.183 ["Time left"] = "Restzeit"; 31.184 ["Title (80 chars max)"] = "Title (max. 80 Zeichen)"; 31.185 ["Traditional wiki syntax"] = "Traditionaller Wiki-Syntax"; 31.186 @@ -277,9 +320,15 @@ 31.187 ["Vote now"] = "Jetzt abstimmen"; 31.188 ["Vote now/later"] = "Jetzt/später abstimmen"; 31.189 ["Voted"] = "Abgestimmt"; 31.190 +["Voted no"] = "Mit Nein gestimmt"; 31.191 +["Voted proposal"] = "Abgestimmte Vorlage"; 31.192 +["Voted yes"] = "Mit Ja gestimmt"; 31.193 +["Voter"] = "Abstimmende"; 31.194 ["Voting"] = "Abstimmung"; 31.195 ["Voting for this issue has already begun."] = "Die Abstimmung für dieses Thema hat schon begonnen."; 31.196 +["Voting for this issue is currently running!"] = "Über dieses Thema wird gerade abgestimmt!"; 31.197 ["Voting has not started yet."] = "Die Abstimmung hat noch nicht begonnen."; 31.198 +["Voting proposal"] = "Abstimmungsvorlage"; 31.199 ["Voting requests"] = "Abstimmanträge"; 31.200 ["Voting time"] = "Zeit für die Abstimmung"; 31.201 ["Website"] = "Webseite"; 31.202 @@ -292,6 +341,7 @@ 31.203 ["You didn't saved any member as contact yet."] = "Du hast noch kein Mitglied als Kontakt gespeichert!"; 31.204 ["You have saved this member as contact"] = "Du hast das Mitglied als Kontakt gespeichert"; 31.205 ["You have saved this member as contact."] = "Du hast das Mitglied als Kontakt gespeichert."; 31.206 +["You have to accept the terms of use to complete registration."] = "Du musst die Nutzungsbedingungen akzeptieren um die Registration abzuschliessen."; 31.207 ["You need to be logged in, to use this system."] = "Du musst eingeloggt sein, um das System zu benutzen"; 31.208 ["You've successfully registered and you can login now with your login and password!"] = "Du hast Dich erfolgreich registriert und kannst Dich jetzt mit Deinen Benutzernamen und Kennwort anmelden!"; 31.209 ["Your are interested"] = "Du bist interessiert"; 31.210 @@ -325,5 +375,6 @@ 31.211 ["not implemented"] = "nicht umgesetzt"; 31.212 ["should"] = "soll"; 31.213 ["should not"] = "soll nicht"; 31.214 +["to reset your password please click on the following link:\n\n"] = "um Dein Kennwort zurückzusetzen klicke bitte den folgenden Link an:\n\n"; 31.215 ["xmpp"] = "Jabber (XMPP)"; 31.216 }
32.1 --- a/model/initiative.lua Fri Dec 25 12:00:00 2009 +0100 32.2 +++ b/model/initiative.lua Sat Jan 02 12:00:00 2010 +0100 32.3 @@ -101,10 +101,29 @@ 32.4 ref = 'supporting_members_snapshot' 32.5 } 32.6 32.7 + 32.8 function Initiative:get_search_selector(search_string) 32.9 return self:new_selector() 32.10 + :join("draft", nil, "draft.initiative_id = initiative.id") 32.11 :add_field( {'"highlight"("initiative"."name", ?)', search_string }, "name_highlighted") 32.12 - :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?)', search_string } 32.13 + :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?) OR "draft"."text_search_data" @@ "text_search_query"(?)', search_string, search_string } 32.14 + :add_group_by('"initiative"."id"') 32.15 + :add_group_by('"initiative"."issue_id"') 32.16 + :add_group_by('"initiative"."name"') 32.17 + :add_group_by('"initiative"."discussion_url"') 32.18 + :add_group_by('"initiative"."created"') 32.19 + :add_group_by('"initiative"."revoked"') 32.20 + :add_group_by('"initiative"."admitted"') 32.21 + :add_group_by('"initiative"."supporter_count"') 32.22 + :add_group_by('"initiative"."informed_supporter_count"') 32.23 + :add_group_by('"initiative"."satisfied_supporter_count"') 32.24 + :add_group_by('"initiative"."satisfied_informed_supporter_count"') 32.25 + :add_group_by('"initiative"."positive_votes"') 32.26 + :add_group_by('"initiative"."negative_votes"') 32.27 + :add_group_by('"initiative"."agreed"') 32.28 + :add_group_by('"initiative"."rank"') 32.29 + :add_group_by('"initiative"."text_search_data"') 32.30 + :add_group_by('"issue"."population"') 32.31 end 32.32 32.33 function Member:get_search_selector(search_string)
33.1 --- a/model/issue.lua Fri Dec 25 12:00:00 2009 +0100 33.2 +++ b/model/issue.lua Sat Jan 02 12:00:00 2010 +0100 33.3 @@ -97,6 +97,19 @@ 33.4 ref = 'interested_members_snapshot' 33.5 } 33.6 33.7 +Issue:add_reference{ 33.8 + mode = 'mm', 33.9 + to = "Member", 33.10 + this_key = 'id', 33.11 + that_key = 'id', 33.12 + connected_by_table = 'direct_voter', 33.13 + connected_by_this_key = 'issue_id', 33.14 + connected_by_that_key = 'member_id', 33.15 + ref = 'direct_voters' 33.16 +} 33.17 + 33.18 + 33.19 + 33.20 function Issue:get_state_name_for_state(value) 33.21 local state_name_table = { 33.22 new = _"New", 33.23 @@ -112,8 +125,24 @@ 33.24 function Issue:get_search_selector(search_string) 33.25 return self:new_selector() 33.26 :join('"initiative"', nil, '"initiative"."issue_id" = "issue"."id"') 33.27 - :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?)', search_string } 33.28 - :set_distinct() 33.29 + :join('"draft"', nil, '"draft"."initiative_id" = "initiative"."id"') 33.30 + :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?) OR "draft"."text_search_data" @@ "text_search_query"(?)', search_string, search_string } 33.31 + :add_group_by('"issue"."id"') 33.32 + :add_group_by('"issue"."area_id"') 33.33 + :add_group_by('"issue"."policy_id"') 33.34 + :add_group_by('"issue"."created"') 33.35 + :add_group_by('"issue"."accepted"') 33.36 + :add_group_by('"issue"."half_frozen"') 33.37 + :add_group_by('"issue"."fully_frozen"') 33.38 + :add_group_by('"issue"."closed"') 33.39 + :add_group_by('"issue"."ranks_available"') 33.40 + :add_group_by('"issue"."snapshot"') 33.41 + :add_group_by('"issue"."latest_snapshot_event"') 33.42 + :add_group_by('"issue"."population"') 33.43 + :add_group_by('"issue"."vote_now"') 33.44 + :add_group_by('"issue"."vote_later"') 33.45 + :add_group_by('"issue"."voter_count"') 33.46 + --:set_distinct() 33.47 end 33.48 33.49 function Issue.object_get:state()
34.1 --- a/model/member.lua Fri Dec 25 12:00:00 2009 +0100 34.2 +++ b/model/member.lua Sat Jan 02 12:00:00 2010 +0100 34.3 @@ -277,3 +277,28 @@ 34.4 :add_where("active") 34.5 end 34.6 34.7 +function Member.object:set_notify_email(notify_email) 34.8 + local expiry = db:query("SELECT now() + '7 days'::interval as expiry", "object").expiry 34.9 + self.notify_email_unconfirmed = notify_email 34.10 + self.notify_email_secret = multirand.string( 24, "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ) 34.11 + self.notify_email_secret_expiry = expiry 34.12 + local content = slot.use_temporary(function() 34.13 + slot.put(_"Hello " .. self.name .. ",\n\n") 34.14 + slot.put(_"Please confirm your email address by clicking the following link:\n\n") 34.15 + slot.put(config.absolute_base_url .. "index/confirm_notify_email.html?secret=" .. self.notify_email_secret .. "\n\n") 34.16 + slot.put(_"If this link is not working, please open following url in your web browser:\n\n") 34.17 + slot.put(config.absolute_base_url .. "index/confirm_notify_email.html\n\n") 34.18 + slot.put(_"On that page please enter the confirmation code:\n\n") 34.19 + slot.put(self.notify_email_secret .. "\n\n") 34.20 + end) 34.21 + local success = net.send_mail{ 34.22 + envelope_from = config.mail_envelope_from, 34.23 + from = config.mail_from, 34.24 + reply_to = config.mail_reply_to, 34.25 + to = self.notify_email_unconfirmed, 34.26 + subject = config.mail_subject_prefix .. _"Email confirmation request", 34.27 + content_type = "text/plain; charset=UTF-8", 34.28 + content = content 34.29 + } 34.30 + return success 34.31 +end
35.1 Binary file static/icons/16/bullet_yellow.png has changed
36.1 Binary file static/icons/16/database_save.png has changed
37.1 Binary file static/icons/16/key_forgot.png has changed
38.1 Binary file static/icons/16/resultset_previous.png has changed
39.1 Binary file static/icons/grabber.png has changed
40.1 --- a/static/js/dragdrop.js Fri Dec 25 12:00:00 2009 +0100 40.2 +++ b/static/js/dragdrop.js Sat Jan 02 12:00:00 2010 +0100 40.3 @@ -59,7 +59,7 @@ 40.4 element.addEventListener("mousedown", function(event) { 40.5 event.target.style.cursor = "move"; 40.6 dragElement(event.currentTarget, function(element, dropX, dropY) { 40.7 - event.target.style.cursor = null; 40.8 + event.target.style.cursor = ''; 40.9 elementDropped(element, dropX, dropY); 40.10 }); 40.11 event.preventDefault();
41.1 --- a/static/style.css Fri Dec 25 12:00:00 2009 +0100 41.2 +++ b/static/style.css Sat Jan 02 12:00:00 2010 +0100 41.3 @@ -792,9 +792,10 @@ 41.4 margin-right: 0.7em; 41.5 } 41.6 41.7 -.draft_updated_info { 41.8 - border: 2px solid #faa; 41.9 - background-color: #fee; 41.10 +.draft_updated_info, 41.11 +.voting_active_info { 41.12 + background-color: #fec; 41.13 + border: 2px solid #b96; 41.14 padding: 1ex; 41.15 } 41.16 41.17 @@ -806,7 +807,8 @@ 41.18 line-height: 120%; 41.19 } 41.20 41.21 -.help { 41.22 +.help, 41.23 +.use_terms { 41.24 border: 1px solid #bcd; 41.25 background-color: #def; 41.26 color: #000; 41.27 @@ -918,3 +920,8 @@ 41.28 #voting a.clickable { 41.29 cursor: pointer; 41.30 } 41.31 + 41.32 +#voting .grabber { 41.33 + vertical-align: middle; 41.34 + cursor: move; 41.35 +} 41.36 \ No newline at end of file