liquid_feedback_frontend
changeset 10:72c5e0ee7c98 beta6
Version beta6
Bugfixes:
- Security fix: Every user was able to change the discussion URL of an initiative
- Creation of new issues in areas without default policies is now possible
- Members can now be sorted in different ways
- No error when trying to compare a draft with itself
- Added missing local statement to variable initialization in app/main/delegation/new.lua
- CSS flaw in initiative action bar fixed
New features:
- Possiblity to invite other users to become initiator
- Revokation of initiatives implemented
- Number of suggestions, supporters, etc. is shown on corresponding tabs of initiative view
- Members can now be sorted by account creation (default sorting is "newest first")
- Configuration option to create an automatic discussion link for all issues
- First draft of global timeline feature (not accessible via link yet)
- Custom stylesheet URL for users marked as developers
In area listing the number of closed issues is shown too
Renamed "author" field of initiative to "last author"
Removed wrongly included file app/main/member/_show_thumb.lua.orig in the distribution
Help texts updated
Bugfixes:
- Security fix: Every user was able to change the discussion URL of an initiative
- Creation of new issues in areas without default policies is now possible
- Members can now be sorted in different ways
- No error when trying to compare a draft with itself
- Added missing local statement to variable initialization in app/main/delegation/new.lua
- CSS flaw in initiative action bar fixed
New features:
- Possiblity to invite other users to become initiator
- Revokation of initiatives implemented
- Number of suggestions, supporters, etc. is shown on corresponding tabs of initiative view
- Members can now be sorted by account creation (default sorting is "newest first")
- Configuration option to create an automatic discussion link for all issues
- First draft of global timeline feature (not accessible via link yet)
- Custom stylesheet URL for users marked as developers
In area listing the number of closed issues is shown too
Renamed "author" field of initiative to "last author"
Removed wrongly included file app/main/member/_show_thumb.lua.orig in the distribution
Help texts updated
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/app/main/_filter_view/34_stylesheet.lua Sun Jan 10 12:00:00 2010 +0100 1.3 @@ -0,0 +1,14 @@ 1.4 +local value 1.5 +if app.session.member then 1.6 + local setting_key = "liquidfeedback_frontend_stylesheet_url" 1.7 + local setting = Setting:by_pk(app.session.member.id, setting_key) 1.8 + value = setting and setting.value 1.9 +end 1.10 + 1.11 +if value then 1.12 + slot.put_into("stylesheet_url", value) 1.13 +else 1.14 + slot.put_into("stylesheet_url", config.absolute_base_url .. "static/style.css") 1.15 +end 1.16 + 1.17 +execute.inner() 1.18 \ No newline at end of file
2.1 --- a/app/main/_layout/default.html Mon Jan 04 12:00:00 2010 +0100 2.2 +++ b/app/main/_layout/default.html Sun Jan 10 12:00:00 2010 +0100 2.3 @@ -3,7 +3,7 @@ 2.4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 2.5 <title><!-- WEBMCP SLOTNODIV app_name --></title> 2.6 <link rel="stylesheet" type="text/css" media="screen" href="__BASEURL__/static/trace.css" /> 2.7 - <link rel="stylesheet" type="text/css" media="screen" href="__BASEURL__/static/style.css" /> 2.8 + <link rel="stylesheet" type="text/css" media="screen" href="<!-- WEBMCP SLOTNODIV stylesheet_url -->" /> 2.9 <!-- WEBMCP SLOTNODIV html_head --> 2.10 </head> 2.11 <body>
3.1 --- a/app/main/area/_list.lua Mon Jan 04 12:00:00 2010 +0100 3.2 +++ b/app/main/area/_list.lua Sun Jan 10 12:00:00 2010 +0100 3.3 @@ -11,6 +11,8 @@ 3.4 :add_field("(SELECT COUNT(*) FROM issue WHERE issue.area_id = area.id AND issue.half_frozen NOTNULL AND issue.fully_frozen ISNULL AND issue.closed ISNULL)", "issues_frozen_count") 3.5 :add_field("(SELECT COUNT(*) FROM issue WHERE issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed ISNULL)", "issues_voting_count") 3.6 :add_field({ "(SELECT COUNT(*) FROM issue LEFT JOIN direct_voter ON direct_voter.issue_id = issue.id AND direct_voter.member_id = ? WHERE issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed ISNULL AND direct_voter.member_id ISNULL)", app.session.member.id }, "issues_to_vote_count") 3.7 + :add_field("(SELECT COUNT(*) FROM issue WHERE issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed NOTNULL)", "issues_finished_count") 3.8 + :add_field("(SELECT COUNT(*) FROM issue WHERE issue.area_id = area.id AND issue.fully_frozen ISNULL AND issue.closed NOTNULL)", "issues_cancelled_count") 3.9 3.10 ui.order{ 3.11 name = name, 3.12 @@ -132,7 +134,33 @@ 3.13 params = { filter = "frozen", filter_voting = "not_voted" } 3.14 } 3.15 end 3.16 - } 3.17 + }, 3.18 + { 3.19 + label = _"Finished", 3.20 + field_attr = { style = "text-align: right;" }, 3.21 + content = function(record) 3.22 + ui.link{ 3.23 + text = tostring(record.issues_finished_count), 3.24 + module = "area", 3.25 + view = "show", 3.26 + id = record.id, 3.27 + params = { filter = "finished", issue_list = "newest" } 3.28 + } 3.29 + end 3.30 + }, 3.31 + { 3.32 + label = _"Cancelled", 3.33 + field_attr = { style = "text-align: right;" }, 3.34 + content = function(record) 3.35 + ui.link{ 3.36 + text = tostring(record.issues_cancelled_count), 3.37 + module = "area", 3.38 + view = "show", 3.39 + id = record.id, 3.40 + params = { filter = "cancelled", issue_list = "newest" } 3.41 + } 3.42 + end 3.43 + }, 3.44 } 3.45 } 3.46 end
4.1 --- a/app/main/delegation/new.lua Mon Jan 04 12:00:00 2010 +0100 4.2 +++ b/app/main/delegation/new.lua Sun Jan 10 12:00:00 2010 +0100 4.3 @@ -74,7 +74,7 @@ 4.4 } 4.5 }, 4.6 content = function() 4.7 - records = { 4.8 + local records = { 4.9 { 4.10 id = "-1", 4.11 name = _"No delegation"
5.1 --- a/app/main/draft/_action/add.lua Mon Jan 04 12:00:00 2010 +0100 5.2 +++ b/app/main/draft/_action/add.lua Sun Jan 10 12:00:00 2010 +0100 5.3 @@ -17,26 +17,27 @@ 5.4 return false 5.5 end 5.6 5.7 -if Initiator:by_pk(initiative.id, app.session.member.id) then 5.8 - local draft = Draft:new() 5.9 - draft.author_id = app.session.member.id 5.10 - draft.initiative_id = initiative.id 5.11 - local formatting_engine = param.get("formatting_engine") 5.12 - local formatting_engine_valid = false 5.13 - for fe, dummy in pairs(config.formatting_engine_executeables) do 5.14 - if formatting_engine == fe then 5.15 - formatting_engine_valid = true 5.16 - end 5.17 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 5.18 +if not initiator or not initiator.accepted then 5.19 + error("access denied") 5.20 +end 5.21 + 5.22 +local draft = Draft:new() 5.23 +draft.author_id = app.session.member.id 5.24 +draft.initiative_id = initiative.id 5.25 +local formatting_engine = param.get("formatting_engine") 5.26 +local formatting_engine_valid = false 5.27 +for fe, dummy in pairs(config.formatting_engine_executeables) do 5.28 + if formatting_engine == fe then 5.29 + formatting_engine_valid = true 5.30 end 5.31 - if not formatting_engine_valid then 5.32 - error("invalid formatting engine!") 5.33 - end 5.34 - draft.formatting_engine = formatting_engine 5.35 - draft.content = param.get("content") 5.36 - draft:save() 5.37 +end 5.38 +if not formatting_engine_valid then 5.39 + error("invalid formatting engine!") 5.40 +end 5.41 +draft.formatting_engine = formatting_engine 5.42 +draft.content = param.get("content") 5.43 +draft:save() 5.44 5.45 - slot.put_into("notice", _"New draft has been added to initiative") 5.46 +slot.put_into("notice", _"New draft has been added to initiative") 5.47 5.48 -else 5.49 - error('access denied') 5.50 -end
6.1 --- a/app/main/draft/_show.lua Mon Jan 04 12:00:00 2010 +0100 6.2 +++ b/app/main/draft/_show.lua Sun Jan 10 12:00:00 2010 +0100 6.3 @@ -6,7 +6,7 @@ 6.4 readonly = true, 6.5 content = function() 6.6 6.7 - ui.field.text{ label = _"Author", name = "author_name" } 6.8 + ui.field.text{ label = _"Last author", name = "author_name" } 6.9 ui.field.timestamp{ label = _"Created at", name = "created" } 6.10 ui.container{ 6.11 attr = { class = "draft_content wiki" },
7.1 --- a/app/main/draft/diff.lua Mon Jan 04 12:00:00 2010 +0100 7.2 +++ b/app/main/draft/diff.lua Sun Jan 10 12:00:00 2010 +0100 7.3 @@ -3,6 +3,16 @@ 7.4 local old_draft_id = param.get("old_draft_id", atom.integer) 7.5 local new_draft_id = param.get("new_draft_id", atom.integer) 7.6 7.7 +if not old_draft_id or not new_draft_id then 7.8 + slot.put( _"Please choose two versions of the draft to compare") 7.9 + return 7.10 +end 7.11 + 7.12 +if old_draft_id == new_draft_id then 7.13 + slot.put( _"Please choose two different versions of the draft to compare") 7.14 + return 7.15 +end 7.16 + 7.17 if old_draft_id > new_draft_id then 7.18 local tmp = old_draft_id 7.19 old_draft_id = new_draft_id
8.1 --- a/app/main/index/index.lua Mon Jan 04 12:00:00 2010 +0100 8.2 +++ b/app/main/index/index.lua Sun Jan 10 12:00:00 2010 +0100 8.3 @@ -1,12 +1,14 @@ 8.4 slot.select("title", function() 8.5 - execute.view{ 8.6 - module = "member_image", 8.7 - view = "_show", 8.8 - params = { 8.9 - member = app.session.member, 8.10 - image_type = "avatar" 8.11 + if app.session.member then 8.12 + execute.view{ 8.13 + module = "member_image", 8.14 + view = "_show", 8.15 + params = { 8.16 + member = app.session.member, 8.17 + image_type = "avatar" 8.18 + } 8.19 } 8.20 - } 8.21 + end 8.22 end) 8.23 8.24 slot.select("title", function() 8.25 @@ -43,48 +45,50 @@ 8.26 8.27 slot.select("actions", function() 8.28 8.29 - ui.link{ 8.30 - content = function() 8.31 - ui.image{ static = "icons/16/application_form.png" } 8.32 - slot.put(_"Edit my profile") 8.33 - end, 8.34 - module = "member", 8.35 - view = "edit" 8.36 - } 8.37 - 8.38 - ui.link{ 8.39 - content = function() 8.40 - ui.image{ static = "icons/16/user_gray.png" } 8.41 - slot.put(_"Upload images") 8.42 - end, 8.43 - module = "member", 8.44 - view = "edit_images" 8.45 - } 8.46 - 8.47 - execute.view{ 8.48 - module = "delegation", 8.49 - view = "_show_box" 8.50 - } 8.51 - 8.52 - ui.link{ 8.53 - content = function() 8.54 - ui.image{ static = "icons/16/wrench.png" } 8.55 - slot.put(_"Settings") 8.56 - end, 8.57 - module = "member", 8.58 - view = "settings" 8.59 - } 8.60 - 8.61 - if config.download_dir then 8.62 + if app.session.member then 8.63 + ui.link{ 8.64 + content = function() 8.65 + ui.image{ static = "icons/16/application_form.png" } 8.66 + slot.put(_"Edit my profile") 8.67 + end, 8.68 + module = "member", 8.69 + view = "edit" 8.70 + } 8.71 + 8.72 ui.link{ 8.73 content = function() 8.74 - ui.image{ static = "icons/16/database_save.png" } 8.75 - slot.put(_"Download") 8.76 + ui.image{ static = "icons/16/user_gray.png" } 8.77 + slot.put(_"Upload images") 8.78 end, 8.79 - module = "index", 8.80 - view = "download" 8.81 + module = "member", 8.82 + view = "edit_images" 8.83 + } 8.84 + 8.85 + execute.view{ 8.86 + module = "delegation", 8.87 + view = "_show_box" 8.88 } 8.89 - end 8.90 + 8.91 + ui.link{ 8.92 + content = function() 8.93 + ui.image{ static = "icons/16/wrench.png" } 8.94 + slot.put(_"Settings") 8.95 + end, 8.96 + module = "member", 8.97 + view = "settings" 8.98 + } 8.99 + 8.100 + if config.download_dir then 8.101 + ui.link{ 8.102 + content = function() 8.103 + ui.image{ static = "icons/16/database_save.png" } 8.104 + slot.put(_"Download") 8.105 + end, 8.106 + module = "index", 8.107 + view = "download" 8.108 + } 8.109 + end 8.110 + end 8.111 end) 8.112 8.113 local lang = locale.get("lang") 8.114 @@ -106,24 +110,25 @@ 8.115 8.116 util.help("index.index", _"Home") 8.117 8.118 - 8.119 -local selector = Area:new_selector() 8.120 - :reset_fields() 8.121 - :add_field("area.id", nil, { "grouped" }) 8.122 - :add_field("area.name", nil, { "grouped" }) 8.123 - :add_field("membership.member_id NOTNULL", "is_member", { "grouped" }) 8.124 - :add_field("count(issue.id)", "issues_to_vote_count") 8.125 - :add_field("count(interest.member_id)", "interested_issues_to_vote_count") 8.126 - :join("issue", nil, "issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed ISNULL") 8.127 - :left_join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id }) 8.128 - :add_where{ "direct_voter.member_id ISNULL" } 8.129 - :left_join("interest", nil, { "interest.issue_id = issue.id AND interest.member_id = ?", app.session.member.id }) 8.130 - :left_join("membership", nil, { "membership.area_id = area.id AND membership.member_id = ? ", app.session.member.id }) 8.131 - 8.132 local areas = {} 8.133 -for i, area in ipairs(selector:exec()) do 8.134 - if area.is_member or area.interested_issues_to_vote_count > 0 then 8.135 - areas[#areas+1] = area 8.136 +if app.session.member then 8.137 + local selector = Area:new_selector() 8.138 + :reset_fields() 8.139 + :add_field("area.id", nil, { "grouped" }) 8.140 + :add_field("area.name", nil, { "grouped" }) 8.141 + :add_field("membership.member_id NOTNULL", "is_member", { "grouped" }) 8.142 + :add_field("count(issue.id)", "issues_to_vote_count") 8.143 + :add_field("count(interest.member_id)", "interested_issues_to_vote_count") 8.144 + :join("issue", nil, "issue.area_id = area.id AND issue.fully_frozen NOTNULL AND issue.closed ISNULL") 8.145 + :left_join("direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", app.session.member.id }) 8.146 + :add_where{ "direct_voter.member_id ISNULL" } 8.147 + :left_join("interest", nil, { "interest.issue_id = issue.id AND interest.member_id = ?", app.session.member.id }) 8.148 + :left_join("membership", nil, { "membership.area_id = area.id AND membership.member_id = ? ", app.session.member.id }) 8.149 + 8.150 + for i, area in ipairs(selector:exec()) do 8.151 + if area.is_member or area.interested_issues_to_vote_count > 0 then 8.152 + areas[#areas+1] = area 8.153 + end 8.154 end 8.155 end 8.156 8.157 @@ -190,9 +195,27 @@ 8.158 } 8.159 end 8.160 8.161 -execute.view{ 8.162 - module = "member", 8.163 - view = "_show", 8.164 - params = { member = app.session.member } 8.165 -} 8.166 +local initiatives_selector = Initiative:new_selector() 8.167 + :join("initiator", nil, { "initiator.initiative_id = initiative.id AND initiator.member_id = ? AND initiator.accepted ISNULL", app.session.member.id }) 8.168 + 8.169 +if initiatives_selector:count() > 0 then 8.170 + ui.container{ 8.171 + attr = { style = "font-weight: bold;" }, 8.172 + content = _"Initiatives that invited you to become initiator:" 8.173 + } 8.174 8.175 + execute.view{ 8.176 + module = "initiative", 8.177 + view = "_list", 8.178 + params = { initiatives_selector = initiatives_selector } 8.179 + } 8.180 +end 8.181 + 8.182 + 8.183 +if app.session.member then 8.184 + execute.view{ 8.185 + module = "member", 8.186 + view = "_show", 8.187 + params = { member = app.session.member } 8.188 + } 8.189 +end
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/app/main/initiative/_action/accept_invitation.lua Sun Jan 10 12:00:00 2010 +0100 9.3 @@ -0,0 +1,32 @@ 9.4 +local initiator = Initiator:by_pk(param.get_id(), app.session.member.id) 9.5 + 9.6 +if not initiator then 9.7 + slot.put_into("error", _"Sorry, but you are currently not invited") 9.8 + return 9.9 +end 9.10 + 9.11 +-- TODO important m1 selectors returning result _SET_! 9.12 +local issue = initiator.initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 9.13 + 9.14 +if issue.closed then 9.15 + slot.put_into("error", _"This issue is already closed.") 9.16 + return false 9.17 +elseif issue.half_frozen then 9.18 + slot.put_into("error", _"This issue is already frozen.") 9.19 + return false 9.20 +end 9.21 + 9.22 +if initiator.initiative.revoked then 9.23 + slot.put_into("error", _"This initiative is revoked") 9.24 + return false 9.25 +end 9.26 + 9.27 +if initiator.accepted then 9.28 + slot.put_into("error", _"You are already initator") 9.29 + return 9.30 +end 9.31 + 9.32 +initiator.accepted = true 9.33 +initiator:save() 9.34 + 9.35 +slot.put_into("notice", _"You are now initiator of this initiative")
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/app/main/initiative/_action/add_initiator.lua Sun Jan 10 12:00:00 2010 +0100 10.3 @@ -0,0 +1,49 @@ 10.4 +local initiative = Initiative:by_id(param.get("initiative_id")) 10.5 +local member = Member:by_id(param.get("member_id")) 10.6 + 10.7 +if not member then 10.8 + slot.put_into("error", _"Please choose a member") 10.9 + return false 10.10 +end 10.11 + 10.12 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 10.13 +if not initiator or initiator.accepted ~= true then 10.14 + error("access denied") 10.15 +end 10.16 + 10.17 +-- TODO important m1 selectors returning result _SET_! 10.18 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 10.19 + 10.20 +if issue.closed then 10.21 + slot.put_into("error", _"This issue is already closed.") 10.22 + return false 10.23 +elseif issue.half_frozen then 10.24 + slot.put_into("error", _"This issue is already frozen.") 10.25 + return false 10.26 +end 10.27 + 10.28 +if initiative.revoked then 10.29 + slot.put_into("error", _"This initiative is revoked") 10.30 + return false 10.31 +end 10.32 + 10.33 +local initiator = Initiator:by_pk(initiative.id, member.id) 10.34 +if initiator then 10.35 + if initiator.accepted == true then 10.36 + slot.put_into("error", _"This member is already initiator of this initiative") 10.37 + elseif initiator.accepted == false then 10.38 + slot.put_into("error", _"This member has rejected to become initiator of this initiative") 10.39 + elseif initiator.accepted == nil then 10.40 + slot.put_into("error", _"This member is already invited to become initiator of this initiative") 10.41 + end 10.42 + return false 10.43 +end 10.44 + 10.45 +local initiator = Initiator:new() 10.46 +initiator.initiative_id = initiative.id 10.47 +initiator.member_id = member.id 10.48 +initiator.accepted = nil 10.49 +initiator:save() 10.50 + 10.51 +slot.put_into("notice", _"Member is now invited to be initiator") 10.52 +
11.1 --- a/app/main/initiative/_action/add_support.lua Mon Jan 04 12:00:00 2010 +0100 11.2 +++ b/app/main/initiative/_action/add_support.lua Sun Jan 10 12:00:00 2010 +0100 11.3 @@ -11,6 +11,11 @@ 11.4 return false 11.5 end 11.6 11.7 +if initiative.revoked then 11.8 + slot.put_into("error", _"This initiative is revoked") 11.9 + return false 11.10 +end 11.11 + 11.12 local member = app.session.member 11.13 11.14 local supporter = Supporter:by_pk(initiative.id, member.id)
12.1 --- a/app/main/initiative/_action/create.lua Mon Jan 04 12:00:00 2010 +0100 12.2 +++ b/app/main/initiative/_action/create.lua Sun Jan 10 12:00:00 2010 +0100 12.3 @@ -29,6 +29,13 @@ 12.4 area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec() 12.5 end 12.6 12.7 +local policy_id = param.get("policy_id", atom.integer) 12.8 + 12.9 +if policy_id == -1 then 12.10 + slot.put_into("error", _"Please choose a policy") 12.11 + return false 12.12 +end 12.13 + 12.14 local name = param.get("name") 12.15 12.16 local name = util.trim(name) 12.17 @@ -41,7 +48,6 @@ 12.18 local initiative = Initiative:new() 12.19 12.20 if not issue then 12.21 - local policy_id = param.get("policy_id", atom.integer) 12.22 if not area:get_reference_selector("allowed_policies") 12.23 :add_where{ "policy.id = ?", policy_id } 12.24 :optional_object_mode() 12.25 @@ -80,6 +86,7 @@ 12.26 local initiator = Initiator:new() 12.27 initiator.initiative_id = initiative.id 12.28 initiator.member_id = app.session.member.id 12.29 +initiator.accepted = true 12.30 initiator:save() 12.31 12.32 local supporter = Supporter:new()
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/app/main/initiative/_action/reject_initiator_invitation.lua Sun Jan 10 12:00:00 2010 +0100 13.3 @@ -0,0 +1,24 @@ 13.4 +local initiative = Initiative:by_id(param.get("initiative_id")) 13.5 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 13.6 + 13.7 +-- TODO important m1 selectors returning result _SET_! 13.8 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 13.9 + 13.10 +if issue.closed then 13.11 + slot.put_into("error", _"This issue is already closed.") 13.12 + return false 13.13 +elseif issue.half_frozen then 13.14 + slot.put_into("error", _"This issue is already frozen.") 13.15 + return false 13.16 +end 13.17 + 13.18 +if initiator.accepted ~= nil then 13.19 + error("access denied") 13.20 +end 13.21 + 13.22 +initiator.accepted = false 13.23 +initiator:save() 13.24 + 13.25 +slot.put_into("notice", _"Invitation has been refused") 13.26 + 13.27 +
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/app/main/initiative/_action/remove_initiator.lua Sun Jan 10 12:00:00 2010 +0100 14.3 @@ -0,0 +1,44 @@ 14.4 +local initiative = Initiative:by_id(param.get("initiative_id")) 14.5 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 14.6 + 14.7 +-- TODO important m1 selectors returning result _SET_! 14.8 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 14.9 + 14.10 +if issue.closed then 14.11 + slot.put_into("error", _"This issue is already closed.") 14.12 + return false 14.13 +elseif issue.half_frozen then 14.14 + slot.put_into("error", _"This issue is already frozen.") 14.15 + return false 14.16 +end 14.17 + 14.18 +if initiative.revoked then 14.19 + slot.put_into("error", _"This initiative is revoked") 14.20 + return false 14.21 +end 14.22 + 14.23 +local initiator_todelete = Initiator:by_pk(initiative.id, param.get("member_id", atom.integer)) 14.24 + 14.25 +if not (initiator and initiator.accepted) and not (initiator.member_id == initiator_todelete.member_id) then 14.26 + error("access denied") 14.27 +end 14.28 + 14.29 +if initiator_todelete.accepted == false and initiator.member_id ~= initiator_todelete.member_id then 14.30 + error("access denied") 14.31 +end 14.32 + 14.33 +local initiators = initiative 14.34 + :get_reference_selector("initiators") 14.35 + :add_where("accepted") 14.36 + :for_update() 14.37 + :exec() 14.38 + 14.39 +if #initiators > 1 or initiator_todelete.accepted ~= true then 14.40 + initiator_todelete:destroy() 14.41 + slot.put_into("notice", _"Member has been removed from initiators") 14.42 +else 14.43 + slot.put_into("error", _"Can't remove last initiator") 14.44 + return false 14.45 +end 14.46 + 14.47 +
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/app/main/initiative/_action/revoke.lua Sun Jan 10 12:00:00 2010 +0100 15.3 @@ -0,0 +1,47 @@ 15.4 +local initiative = Initiative:by_id(param.get_id()) 15.5 + 15.6 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 15.7 +if not initiator or initiator.accepted ~= true then 15.8 + error("access denied") 15.9 +end 15.10 + 15.11 +-- TODO important m1 selectors returning result _SET_! 15.12 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 15.13 + 15.14 +if issue.closed then 15.15 + slot.put_into("error", _"This issue is already closed.") 15.16 + return false 15.17 +elseif issue.half_frozen then 15.18 + slot.put_into("error", _"This issue is already frozen.") 15.19 + return false 15.20 +end 15.21 + 15.22 +if initiative.revoked then 15.23 + slot.put_into("error", _"This initiative is already revoked") 15.24 + return false 15.25 +end 15.26 + 15.27 +local suggested_initiative_id = param.get("suggested_initiative_id", atom.integer) 15.28 + 15.29 +if suggested_initiative_id ~= -1 then 15.30 + local suggested_initiative = Initiative:by_id(suggested_initiative_id) 15.31 + if not suggested_initiative then 15.32 + error("object not found") 15.33 + end 15.34 + if initiative.id == suggested_initiative.id then 15.35 + slot.put_into("error", _"You can't suggest the initiative you are revoking") 15.36 + return false 15.37 + end 15.38 + initiative.suggested_initiative_id = suggested_initiative.id 15.39 +end 15.40 + 15.41 +if not param.get("are_you_sure", atom.boolean) then 15.42 + slot.put_into("error", _"You have to mark 'Are you sure' to revoke!") 15.43 + return false 15.44 +end 15.45 + 15.46 +initiative.revoked = "now" 15.47 +initiative:save() 15.48 + 15.49 +slot.put_into("notice", _"Initiative is revoked now") 15.50 +
16.1 --- a/app/main/initiative/_action/update.lua Mon Jan 04 12:00:00 2010 +0100 16.2 +++ b/app/main/initiative/_action/update.lua Sun Jan 10 12:00:00 2010 +0100 16.3 @@ -1,4 +1,26 @@ 16.4 local initiative = Initiative:by_id(param.get_id()) 16.5 + 16.6 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 16.7 +if not initiator or not initiator.accepted then 16.8 + error("access denied") 16.9 +end 16.10 + 16.11 +-- TODO important m1 selectors returning result _SET_! 16.12 +local issue = initiative:get_reference_selector("issue"):for_share():single_object_mode():exec() 16.13 + 16.14 +if issue.closed then 16.15 + slot.put_into("error", _"This issue is already closed.") 16.16 + return false 16.17 +elseif issue.half_frozen then 16.18 + slot.put_into("error", _"This issue is already frozen.") 16.19 + return false 16.20 +end 16.21 + 16.22 +if initiative.revoked then 16.23 + slot.put_into("error", _"This initiative is revoked") 16.24 + return false 16.25 +end 16.26 + 16.27 param.update(initiative, "discussion_url") 16.28 initiative:save() 16.29
17.1 --- a/app/main/initiative/_list.lua Mon Jan 04 12:00:00 2010 +0100 17.2 +++ b/app/main/initiative/_list.lua Sun Jan 10 12:00:00 2010 +0100 17.3 @@ -42,13 +42,25 @@ 17.4 name = "issue_" .. tostring(issue.id) .. "_initiative_list" 17.5 end 17.6 17.7 -ui.order{ 17.8 +ui_order = ui.order 17.9 + 17.10 +if param.get("no_sort", atom.boolean) then 17.11 + ui_order = function(args) args.content() end 17.12 + if issue.ranks_available then 17.13 + initiatives_selector:add_order_by("initiative.rank, initiative.admitted DESC, vote_ratio(initiative.positive_votes, initiative.negative_votes) DESC, initiative.id") 17.14 + else 17.15 + initiatives_selector:add_order_by("initiative.supporter_count::float / issue.population::float DESC, initiative.id") 17.16 + end 17.17 +end 17.18 + 17.19 +ui_order{ 17.20 name = name, 17.21 selector = initiatives_selector, 17.22 options = order_options, 17.23 content = function() 17.24 ui.paginate{ 17.25 selector = initiatives_selector, 17.26 + per_page = param.get("per_page", atom.number), 17.27 content = function() 17.28 local initiatives = initiatives_selector:exec() 17.29 local columns = {} 17.30 @@ -94,7 +106,12 @@ 17.31 } 17.32 columns[#columns+1] = { 17.33 content = function(record) 17.34 + local link_class 17.35 + if record.revoked then 17.36 + link_class = "revoked" 17.37 + end 17.38 ui.link{ 17.39 + attr = { class = link_class }, 17.40 content = function() 17.41 local name 17.42 if record.name_highlighted then
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/app/main/initiative/add_initiator.lua Sun Jan 10 12:00:00 2010 +0100 18.3 @@ -0,0 +1,60 @@ 18.4 +local initiative = Initiative:by_id(param.get("initiative_id")) 18.5 + 18.6 +slot.put_into("title", _"Invite an initiator to initiative") 18.7 + 18.8 +slot.select("actions", function() 18.9 + ui.link{ 18.10 + content = function() 18.11 + ui.image{ static = "icons/16/cancel.png" } 18.12 + slot.put(_"Cancel") 18.13 + end, 18.14 + module = "initiative", 18.15 + view = "show", 18.16 + id = initiative.id, 18.17 + params = { 18.18 + tab = "initiators" 18.19 + } 18.20 + } 18.21 +end) 18.22 + 18.23 +util.help("initiative.add_initiator", _"Invite an initiator to initiative") 18.24 + 18.25 +ui.form{ 18.26 + attr = { class = "vertical" }, 18.27 + module = "initiative", 18.28 + action = "add_initiator", 18.29 + params = { 18.30 + initiative_id = initiative.id, 18.31 + }, 18.32 + routing = { 18.33 + ok = { 18.34 + mode = "redirect", 18.35 + module = "initiative", 18.36 + view = "show", 18.37 + id = initiative.id, 18.38 + params = { 18.39 + tab = "initiators", 18.40 + } 18.41 + } 18.42 + }, 18.43 + content = function() 18.44 + local records = { 18.45 + { 18.46 + id = "-1", 18.47 + name = _"Choose member" 18.48 + } 18.49 + } 18.50 + local contact_members = app.session.member:get_reference_selector("saved_members"):add_order_by("name"):exec() 18.51 + for i, record in ipairs(contact_members) do 18.52 + records[#records+1] = record 18.53 + end 18.54 + ui.field.select{ 18.55 + label = _"Member", 18.56 + name = "member_id", 18.57 + foreign_records = records, 18.58 + foreign_id = "id", 18.59 + foreign_name = "name" 18.60 + } 18.61 + ui.submit{ text = _"Save" } 18.62 + end 18.63 +} 18.64 \ No newline at end of file
19.1 --- a/app/main/initiative/new.lua Mon Jan 04 12:00:00 2010 +0100 19.2 +++ b/app/main/initiative/new.lua Sun Jan 10 12:00:00 2010 +0100 19.3 @@ -30,14 +30,17 @@ 19.4 if issue_id then 19.5 ui.field.text{ label = _"Issue", value = issue_id } 19.6 else 19.7 - local value 19.8 + tmp = { { id = -1, name = _"Please choose a policy" } } 19.9 + for i, allowed_policy in ipairs(area.allowed_policies) do 19.10 + tmp[#tmp+1] = allowed_policy 19.11 + end 19.12 ui.field.select{ 19.13 label = _"Policy", 19.14 name = "policy_id", 19.15 - foreign_records = area.allowed_policies, 19.16 + foreign_records = tmp, 19.17 foreign_id = "id", 19.18 foreign_name = "name", 19.19 - value = area.default_policy.id 19.20 + value = (area.default_policy or {}).id 19.21 } 19.22 end 19.23 ui.field.text{ label = _"Name", name = "name" }
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/app/main/initiative/remove_initiator.lua Sun Jan 10 12:00:00 2010 +0100 20.3 @@ -0,0 +1,65 @@ 20.4 +local initiative = Initiative:by_id(param.get("initiative_id")) 20.5 + 20.6 +local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 20.7 +if not initiator or initiator.accepted ~= true then 20.8 + error("access denied") 20.9 +end 20.10 + 20.11 +slot.put_into("title", _"Remove initiator from initiative") 20.12 + 20.13 +slot.select("actions", function() 20.14 + ui.link{ 20.15 + content = function() 20.16 + ui.image{ static = "icons/16/cancel.png" } 20.17 + slot.put(_"Cancel") 20.18 + end, 20.19 + module = "initiative", 20.20 + view = "show", 20.21 + id = initiative.id, 20.22 + params = { 20.23 + tab = "initiators" 20.24 + } 20.25 + } 20.26 +end) 20.27 + 20.28 +util.help("initiative.remove_initiator", _"Remove initiator from initiative") 20.29 + 20.30 +ui.form{ 20.31 + attr = { class = "vertical" }, 20.32 + module = "initiative", 20.33 + action = "remove_initiator", 20.34 + params = { 20.35 + initiative_id = initiative.id, 20.36 + }, 20.37 + routing = { 20.38 + ok = { 20.39 + mode = "redirect", 20.40 + module = "initiative", 20.41 + view = "show", 20.42 + id = initiative.id, 20.43 + params = { 20.44 + tab = "initiators", 20.45 + } 20.46 + } 20.47 + }, 20.48 + content = function() 20.49 + local records = { 20.50 + { 20.51 + id = "-1", 20.52 + name = _"Choose initiator" 20.53 + } 20.54 + } 20.55 + local members = initiative:get_reference_selector("initiating_members"):add_where("accepted OR accepted ISNULL"):exec() 20.56 + for i, record in ipairs(members) do 20.57 + records[#records+1] = record 20.58 + end 20.59 + ui.field.select{ 20.60 + label = _"Member", 20.61 + name = "member_id", 20.62 + foreign_records = records, 20.63 + foreign_id = "id", 20.64 + foreign_name = "name" 20.65 + } 20.66 + ui.submit{ text = _"Save" } 20.67 + end 20.68 +} 20.69 \ No newline at end of file
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/app/main/initiative/revoke.lua Sun Jan 10 12:00:00 2010 +0100 21.3 @@ -0,0 +1,62 @@ 21.4 +local initiative = Initiative:by_id(param.get_id()) 21.5 + 21.6 +slot.put_into("title", _"Revoke initiative") 21.7 + 21.8 +slot.select("actions", function() 21.9 + ui.link{ 21.10 + content = function() 21.11 + ui.image{ static = "icons/16/cancel.png" } 21.12 + slot.put(_"Cancel") 21.13 + end, 21.14 + module = "initiative", 21.15 + view = "show", 21.16 + id = initiative.id, 21.17 + params = { 21.18 + tab = "initiators" 21.19 + } 21.20 + } 21.21 +end) 21.22 + 21.23 +util.help("initiative.revoke") 21.24 + 21.25 +ui.form{ 21.26 + attr = { class = "vertical" }, 21.27 + module = "initiative", 21.28 + action = "revoke", 21.29 + id = initiative.id, 21.30 + routing = { 21.31 + ok = { 21.32 + mode = "redirect", 21.33 + module = "initiative", 21.34 + view = "show", 21.35 + id = initiative.id 21.36 + } 21.37 + }, 21.38 + content = function() 21.39 + local initiatives = app.session.member 21.40 + :get_reference_selector("supported_initiatives") 21.41 + :join("issue", nil, "issue.id = initiative.issue_id") 21.42 + :add_field("'Issue #' || issue.id || ': ' || initiative.name", "myname") 21.43 + :exec() 21.44 + 21.45 + local tmp = { { id = -1, myname = _"Suggest no initiative" }} 21.46 + for i, initiative in ipairs(initiatives) do 21.47 + tmp[#tmp+1] = initiative 21.48 + end 21.49 + ui.field.select{ 21.50 + label = _"Suggested initiative", 21.51 + name = "suggested_initiative_id", 21.52 + foreign_records = tmp, 21.53 + foreign_id = "id", 21.54 + foreign_name = "myname", 21.55 + value = param.get("suggested_initiative_id", atom.integer) 21.56 + } 21.57 + slot.put("") 21.58 + ui.field.boolean{ 21.59 + label = _"Are you sure?", 21.60 + name = "are_you_sure", 21.61 + } 21.62 + 21.63 + ui.submit{ text = _"Revoke initiative" } 21.64 + end 21.65 +} 21.66 \ No newline at end of file
22.1 --- a/app/main/initiative/show.lua Mon Jan 04 12:00:00 2010 +0100 22.2 +++ b/app/main/initiative/show.lua Sun Jan 10 12:00:00 2010 +0100 22.3 @@ -18,17 +18,31 @@ 22.4 params = { issue = initiative.issue } 22.5 } 22.6 22.7 +if initiative.revoked then 22.8 + ui.container{ 22.9 + attr = { class = "revoked_info" }, 22.10 + content = function() 22.11 + slot.put(_("This initiative has been revoked at #{revoked}", { revoked = format.timestamp(initiative.revoked) })) 22.12 + local suggested_initiative = initiative.suggested_initiative 22.13 + if suggested_initiative then 22.14 + slot.put("<br /><br />") 22.15 + slot.put(_("The initiators suggest to support the following initiative:")) 22.16 + slot.put("<br />") 22.17 + ui.link{ 22.18 + content = _("Issue ##{id}", { id = suggested_initiative.issue.id } ) .. ": " .. encode.html(suggested_initiative.name), 22.19 + module = "initiative", 22.20 + view = "show", 22.21 + id = suggested_initiative.id 22.22 + } 22.23 + end 22.24 + end 22.25 + } 22.26 +end 22.27 + 22.28 local initiator = Initiator:by_pk(initiative.id, app.session.member.id) 22.29 22.30 --slot.put_into("html_head", '<link rel="alternate" type="application/rss+xml" title="RSS" href="../show/' .. tostring(initiative.id) .. '.rss" />') 22.31 22.32 -execute.view{ 22.33 - module = "supporter", 22.34 - view = "_show_box", 22.35 - params = { initiative = initiative } 22.36 -} 22.37 - 22.38 -slot.put_into("sub_title", encode.html(_"Initiative: '#{name}'":gsub("#{name}", initiative.shortened_name) )) 22.39 22.40 slot.select("actions", function() 22.41 if not initiative.issue.fully_frozen and not initiative.issue.closed then 22.42 @@ -45,48 +59,126 @@ 22.43 end 22.44 end) 22.45 22.46 +slot.put_into("sub_title", encode.html(_"Initiative: '#{name}'":gsub("#{name}", initiative.shortened_name) )) 22.47 + 22.48 +slot.select("support", function() 22.49 + ui.container{ 22.50 + attr = { class = "actions" }, 22.51 + content = function() 22.52 + execute.view{ 22.53 + module = "supporter", 22.54 + view = "_show_box", 22.55 + params = { initiative = initiative } 22.56 + } 22.57 + if initiator and initiator.accepted and not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then 22.58 + ui.link{ 22.59 + attr = { class = "action", style = "float: left;" }, 22.60 + content = function() 22.61 + ui.image{ static = "icons/16/script_delete.png" } 22.62 + slot.put(_"Revoke initiative") 22.63 + end, 22.64 + module = "initiative", 22.65 + view = "revoke", 22.66 + id = initiative.id 22.67 + } 22.68 + end 22.69 + end 22.70 + } 22.71 +end) 22.72 22.73 util.help("initiative.show") 22.74 22.75 +if initiator and initiator.accepted == nil then 22.76 + ui.container{ 22.77 + attr = { class = "initiator_invite_info" }, 22.78 + content = function() 22.79 + slot.put(_"You are invited to become initiator of this initiative.") 22.80 + slot.put(" ") 22.81 + ui.link{ 22.82 + content = function() 22.83 + ui.image{ static = "icons/16/tick.png" } 22.84 + slot.put(_"Accept invitation") 22.85 + end, 22.86 + module = "initiative", 22.87 + action = "accept_invitation", 22.88 + id = initiative.id, 22.89 + routing = { 22.90 + default = { 22.91 + mode = "redirect", 22.92 + module = request.get_module(), 22.93 + view = request.get_view(), 22.94 + id = param.get_id_cgi(), 22.95 + params = param.get_all_cgi() 22.96 + } 22.97 + } 22.98 + } 22.99 + slot.put(" ") 22.100 + ui.link{ 22.101 + content = function() 22.102 + ui.image{ static = "icons/16/cross.png" } 22.103 + slot.put(_"Refuse invitation") 22.104 + end, 22.105 + module = "initiative", 22.106 + action = "reject_initiator_invitation", 22.107 + params = { 22.108 + initiative_id = initiative.id, 22.109 + member_id = app.session.member.id 22.110 + }, 22.111 + routing = { 22.112 + default = { 22.113 + mode = "redirect", 22.114 + module = request.get_module(), 22.115 + view = request.get_view(), 22.116 + id = param.get_id_cgi(), 22.117 + params = param.get_all_cgi() 22.118 + } 22.119 + } 22.120 + } 22.121 + end 22.122 + } 22.123 + slot.put("<br />") 22.124 +end 22.125 22.126 -ui.container{ 22.127 - attr = { class = "vertical" }, 22.128 - content = function() 22.129 - ui.container{ 22.130 - attr = { class = "ui_field_label" }, 22.131 - content = _"Discussion URL" 22.132 - } 22.133 - ui.tag{ 22.134 - tag = "span", 22.135 - content = function() 22.136 - if initiative.discussion_url and #initiative.discussion_url > 0 then 22.137 - ui.link{ 22.138 - attr = { 22.139 - class = "actions", 22.140 - target = "_blank", 22.141 - title = initiative.discussion_url 22.142 - }, 22.143 - content = function() 22.144 - slot.put(encode.html(initiative.discussion_url)) 22.145 - end, 22.146 - external = initiative.discussion_url 22.147 - } 22.148 +if (initiative.discussion_url and #initiative.discussion_url > 0) 22.149 + or (initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked) then 22.150 + ui.container{ 22.151 + attr = { class = "vertical" }, 22.152 + content = function() 22.153 + ui.container{ 22.154 + attr = { class = "ui_field_label" }, 22.155 + content = _"Discussion with initiators" 22.156 + } 22.157 + ui.tag{ 22.158 + tag = "span", 22.159 + content = function() 22.160 + if initiative.discussion_url and #initiative.discussion_url > 0 then 22.161 + ui.link{ 22.162 + attr = { 22.163 + class = "actions", 22.164 + target = "_blank", 22.165 + title = initiative.discussion_url 22.166 + }, 22.167 + content = function() 22.168 + slot.put(encode.html(initiative.discussion_url)) 22.169 + end, 22.170 + external = initiative.discussion_url 22.171 + } 22.172 + end 22.173 + slot.put(" ") 22.174 + if initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked then 22.175 + ui.link{ 22.176 + attr = { class = "actions" }, 22.177 + content = _"(change URL)", 22.178 + module = "initiative", 22.179 + view = "edit", 22.180 + id = initiative.id 22.181 + } 22.182 + end 22.183 end 22.184 - slot.put(" ") 22.185 - if initiator then 22.186 - ui.link{ 22.187 - attr = { class = "actions" }, 22.188 - content = _"(change URL)", 22.189 - module = "initiative", 22.190 - view = "edit", 22.191 - id = initiative.id 22.192 - } 22.193 - end 22.194 - end 22.195 - } 22.196 - end 22.197 -} 22.198 - 22.199 + } 22.200 + end 22.201 + } 22.202 +end 22.203 22.204 22.205 ui.container{ 22.206 @@ -202,7 +294,7 @@ 22.207 name = "current_draft", 22.208 label = current_draft_name, 22.209 content = function() 22.210 - if initiator then 22.211 + if initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked then 22.212 ui.link{ 22.213 content = function() 22.214 ui.image{ static = "icons/16/script_add.png" } 22.215 @@ -238,9 +330,11 @@ 22.216 } 22.217 end 22.218 22.219 +local suggestion_count = initiative:get_reference_selector("suggestions"):count() 22.220 + 22.221 tabs[#tabs+1] = { 22.222 name = "suggestion", 22.223 - label = _"Suggestions", 22.224 + label = _"Suggestions" .. " (" .. tostring(suggestion_count) .. ")", 22.225 content = function() 22.226 execute.view{ 22.227 module = "suggestion", 22.228 @@ -251,7 +345,7 @@ 22.229 } 22.230 } 22.231 slot.put("<br />") 22.232 - if not initiative.issue.fully_frozen and not initiative.issue.closed then 22.233 + if not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then 22.234 ui.link{ 22.235 content = function() 22.236 ui.image{ static = "icons/16/comment_add.png" } 22.237 @@ -264,57 +358,126 @@ 22.238 end 22.239 } 22.240 22.241 +local members_selector = initiative:get_reference_selector("supporting_members_snapshot") 22.242 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 22.243 + :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") 22.244 + :add_field("direct_interest_snapshot.weight") 22.245 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 22.246 + :add_where("direct_supporter_snapshot.satisfied") 22.247 + 22.248 +local satisfied_supporter_count = members_selector:count() 22.249 + 22.250 tabs[#tabs+1] = { 22.251 name = "satisfied_supporter", 22.252 - label = _"Supporter", 22.253 + label = _"Supporter" .. " (" .. tostring(satisfied_supporter_count) .. ")", 22.254 + content = function() 22.255 + execute.view{ 22.256 + module = "member", 22.257 + view = "_list", 22.258 + params = { 22.259 + initiative = initiative, 22.260 + members_selector = members_selector 22.261 + } 22.262 + } 22.263 + end 22.264 +} 22.265 + 22.266 +local members_selector = initiative:get_reference_selector("supporting_members_snapshot") 22.267 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 22.268 + :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") 22.269 + :add_field("direct_interest_snapshot.weight") 22.270 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 22.271 + :add_where("NOT direct_supporter_snapshot.satisfied") 22.272 + 22.273 +local potential_supporter_count = members_selector:count() 22.274 + 22.275 +tabs[#tabs+1] = { 22.276 + name = "supporter", 22.277 + label = _"Potential supporter" .. " (" .. tostring(potential_supporter_count) .. ")", 22.278 content = function() 22.279 execute.view{ 22.280 module = "member", 22.281 view = "_list", 22.282 params = { 22.283 initiative = initiative, 22.284 - members_selector = initiative:get_reference_selector("supporting_members_snapshot") 22.285 - :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 22.286 - :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") 22.287 - :add_field("direct_interest_snapshot.weight") 22.288 - :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 22.289 - :add_where("direct_supporter_snapshot.satisfied") 22.290 + members_selector = members_selector 22.291 } 22.292 } 22.293 end 22.294 } 22.295 22.296 +local initiator_count = initiative:get_reference_selector("initiators"):add_where("accepted"):count() 22.297 + 22.298 tabs[#tabs+1] = { 22.299 - name = "supporter", 22.300 - label = _"Potential supporter", 22.301 + name = "initiators", 22.302 + label = _"Initiators" .. " (" .. tostring(initiator_count) .. ")", 22.303 content = function() 22.304 + if initiator and initiator.accepted and not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then 22.305 + ui.link{ 22.306 + attr = { class = "action" }, 22.307 + content = function() 22.308 + ui.image{ static = "icons/16/user_add.png" } 22.309 + slot.put(_"Invite initiator") 22.310 + end, 22.311 + module = "initiative", 22.312 + view = "add_initiator", 22.313 + params = { initiative_id = initiative.id } 22.314 + } 22.315 + if initiator_count > 1 then 22.316 + ui.link{ 22.317 + content = function() 22.318 + ui.image{ static = "icons/16/user_delete.png" } 22.319 + slot.put(_"Remove initiator") 22.320 + end, 22.321 + module = "initiative", 22.322 + view = "remove_initiator", 22.323 + params = { initiative_id = initiative.id } 22.324 + } 22.325 + end 22.326 + end 22.327 + if initiator and initiator.accepted == false then 22.328 + ui.link{ 22.329 + content = function() 22.330 + ui.image{ static = "icons/16/user_delete.png" } 22.331 + slot.put(_"Cancel refuse of invitation") 22.332 + end, 22.333 + module = "initiative", 22.334 + action = "remove_initiator", 22.335 + params = { 22.336 + initiative_id = initiative.id, 22.337 + member_id = app.session.member.id 22.338 + }, 22.339 + routing = { 22.340 + ok = { 22.341 + mode = "redirect", 22.342 + module = "initiative", 22.343 + view = "show", 22.344 + id = initiative.id 22.345 + } 22.346 + } 22.347 + } 22.348 + end 22.349 + local members_selector = initiative:get_reference_selector("initiating_members") 22.350 + :add_field("initiator.accepted", "accepted") 22.351 + if not (initiator and initiator.accepted) then 22.352 + members_selector:add_where("accepted") 22.353 + end 22.354 execute.view{ 22.355 module = "member", 22.356 view = "_list", 22.357 params = { 22.358 - initiative = initiative, 22.359 - members_selector = initiative:get_reference_selector("supporting_members_snapshot") 22.360 - :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 22.361 - :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") 22.362 - :add_field("direct_interest_snapshot.weight") 22.363 - :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 22.364 - :add_where("NOT direct_supporter_snapshot.satisfied") 22.365 + members_selector = members_selector, 22.366 + initiator = initiator 22.367 } 22.368 } 22.369 end 22.370 } 22.371 22.372 -tabs[#tabs+1] = { 22.373 - name = "initiators", 22.374 - label = _"Initiators", 22.375 - content = function() 22.376 - execute.view{ module = "member", view = "_list", params = { members_selector = initiative:get_reference_selector("initiating_members") } } 22.377 - end 22.378 -} 22.379 +local drafts_count = initiative:get_reference_selector("drafts"):count() 22.380 22.381 tabs[#tabs+1] = { 22.382 name = "drafts", 22.383 - label = _"Old drafts", 22.384 + label = _"Draft history" .. " (" .. tostring(drafts_count) .. ")", 22.385 content = function() 22.386 execute.view{ module = "draft", view = "_list", params = { drafts = initiative.drafts } } 22.387 end 22.388 @@ -338,7 +501,7 @@ 22.389 label = _"Created at", 22.390 value = format.timestamp(initiative.created) 22.391 } 22.392 - ui.field.date{ label = _"Revoked at", name = "revoked" } 22.393 +-- ui.field.date{ label = _"Revoked at", name = "revoked" } 22.394 ui.field.boolean{ label = _"Admitted", name = "admitted" } 22.395 end 22.396 }
23.1 --- a/app/main/issue/_list.lua Mon Jan 04 12:00:00 2010 +0100 23.2 +++ b/app/main/issue/_list.lua Sun Jan 10 12:00:00 2010 +0100 23.3 @@ -5,6 +5,10 @@ 23.4 ui_filter = function(args) args.content() end 23.5 end 23.6 23.7 +if param.get("no_filter", atom.boolean) then 23.8 + ui_filter = function(args) args.content() end 23.9 +end 23.10 + 23.11 local filter_voting = false 23.12 ui_filter{ 23.13 selector = issues_selector, 23.14 @@ -86,6 +90,9 @@ 23.15 if not filter_voting then 23.16 ui_filter = function(args) args.content() end 23.17 end 23.18 + if param.get("no_filter", atom.boolean) then 23.19 + ui_filter = function(args) args.content() end 23.20 + end 23.21 ui_filter{ 23.22 selector = issues_selector, 23.23 name = "filter_voting", 23.24 @@ -145,8 +152,11 @@ 23.25 }, 23.26 }, 23.27 content = function() 23.28 - 23.29 - ui.order{ 23.30 + local ui_order = ui.order 23.31 + if param.get("no_sort", atom.boolean) then 23.32 + ui_order = function(args) args.content() end 23.33 + end 23.34 + ui_order{ 23.35 name = "issue_list", 23.36 selector = issues_selector, 23.37 options = { 23.38 @@ -181,7 +191,12 @@ 23.39 } 23.40 }, 23.41 content = function() 23.42 - ui.paginate{ 23.43 + local ui_paginate = ui.paginate 23.44 + if param.get("per_page") == "all" then 23.45 + ui_paginate = function(args) args.content() end 23.46 + end 23.47 + ui_paginate{ 23.48 + per_page = tonumber(param.get("per_page")), 23.49 selector = issues_selector, 23.50 content = function() 23.51 local highlight_string = param.get("highlight_string", "string") 23.52 @@ -201,7 +216,7 @@ 23.53 slot.put("<br />") 23.54 end 23.55 ui.link{ 23.56 - text = _"Issue ##{id}":gsub("#{id}", tostring(record.id)), 23.57 + text = _("Issue ##{id}", { id = tostring(record.id) }), 23.58 module = "issue", 23.59 view = "show", 23.60 id = record.id 23.61 @@ -213,6 +228,11 @@ 23.62 end 23.63 slot.put("<br />") 23.64 slot.put("<br />") 23.65 + if record.old_state then 23.66 + ui.field.text{ value = format.time(record.sort) } 23.67 + ui.field.text{ value = Issue:get_state_name_for_state(record.old_state) .. " > " .. Issue:get_state_name_for_state(record.new_state) } 23.68 + else 23.69 + end 23.70 end 23.71 }, 23.72 { 23.73 @@ -245,7 +265,9 @@ 23.74 issue = record, 23.75 initiatives_selector = initiatives_selector, 23.76 highlight_string = highlight_string, 23.77 - limit = 3 23.78 + limit = 3, 23.79 + per_page = param.get("initiatives_per_page", atom.number), 23.80 + no_sort = param.get("initiatives_no_sort", atom.boolean) 23.81 } 23.82 } 23.83 end
24.1 --- a/app/main/issue/_show_head.lua Mon Jan 04 12:00:00 2010 +0100 24.2 +++ b/app/main/issue/_show_head.lua Sun Jan 10 12:00:00 2010 +0100 24.3 @@ -77,6 +77,17 @@ 24.4 end 24.5 --]] 24.6 24.7 + if config.issue_discussion_url_func then 24.8 + local url = config.issue_discussion_url_func(issue) 24.9 + ui.link{ 24.10 + attr = { target = "_blank" }, 24.11 + external = url, 24.12 + content = function() 24.13 + ui.image{ static = "icons/16/comments.png" } 24.14 + slot.put(_"Discussion on issue") 24.15 + end, 24.16 + } 24.17 + end 24.18 end) 24.19 24.20
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/app/main/member/_action/update_stylesheet_url.lua Sun Jan 10 12:00:00 2010 +0100 25.3 @@ -0,0 +1,25 @@ 25.4 + 25.5 +local setting_key = "liquidfeedback_frontend_developer_features" 25.6 +local setting = Setting:by_pk(app.session.member.id, setting_key) 25.7 + 25.8 +if not setting then 25.9 + error("access denied") 25.10 +end 25.11 + 25.12 +local stylesheet_url = util.trim(param.get("stylesheet_url")) 25.13 +local setting_key = "liquidfeedback_frontend_stylesheet_url" 25.14 +local setting = Setting:by_pk(app.session.member.id, setting_key) 25.15 + 25.16 +if stylesheet_url and #stylesheet_url > 0 then 25.17 + if not setting then 25.18 + setting = Setting:new() 25.19 + setting.member_id = app.session.member.id 25.20 + setting.key = setting_key 25.21 + end 25.22 + setting.value = stylesheet_url 25.23 + setting:save() 25.24 +elseif setting then 25.25 + setting:destroy() 25.26 +end 25.27 + 25.28 +slot.put_into("notice", _"Stylesheet URL has been updated")
26.1 --- a/app/main/member/_list.lua Mon Jan 04 12:00:00 2010 +0100 26.2 +++ b/app/main/member/_list.lua Sun Jan 10 12:00:00 2010 +0100 26.3 @@ -2,9 +2,20 @@ 26.4 local initiative = param.get("initiative", "table") 26.5 local issue = param.get("issue", "table") 26.6 local trustee = param.get("trustee", "table") 26.7 +local initiator = param.get("initiator", "table") 26.8 26.9 local options = { 26.10 { 26.11 + name = "newest", 26.12 + label = _"Newest", 26.13 + order_by = "created DESC, id DESC" 26.14 + }, 26.15 + { 26.16 + name = "oldest", 26.17 + label = _"Oldest", 26.18 + order_by = "created, id" 26.19 + }, 26.20 + { 26.21 name = "name", 26.22 label = _"A-Z", 26.23 order_by = "name" 26.24 @@ -117,7 +128,13 @@ 26.25 execute.view{ 26.26 module = "member", 26.27 view = "_show_thumb", 26.28 - params = { member = member, initiative = initiative, issue = issue, trustee = trustee } 26.29 + params = { 26.30 + member = member, 26.31 + initiative = initiative, 26.32 + issue = issue, 26.33 + trustee = trustee, 26.34 + initiator = initiator 26.35 + } 26.36 } 26.37 end 26.38 ---]]
27.1 --- a/app/main/member/_show.lua Mon Jan 04 12:00:00 2010 +0100 27.2 +++ b/app/main/member/_show.lua Sun Jan 10 12:00:00 2010 +0100 27.3 @@ -151,7 +151,7 @@ 27.4 execute.view{ 27.5 module = "initiative", 27.6 view = "_list", 27.7 - params = { initiatives_selector = member:get_reference_selector("initiated_initiatives") } 27.8 + params = { initiatives_selector = member:get_reference_selector("initiated_initiatives"):add_where("initiator.accepted = true") } 27.9 } 27.10 end 27.11 },
28.1 --- a/app/main/member/_show_thumb.lua Mon Jan 04 12:00:00 2010 +0100 28.2 +++ b/app/main/member/_show_thumb.lua Sun Jan 10 12:00:00 2010 +0100 28.3 @@ -1,3 +1,4 @@ 28.4 +local initiator = param.get("initiator", "table") 28.5 local member = param.get("member", "table") 28.6 28.7 local issue = param.get("issue", "table") 28.8 @@ -11,8 +12,13 @@ 28.9 name = encode.html(member.name) 28.10 end 28.11 28.12 +local container_class = "member_thumb" 28.13 +if initiator and member.accepted ~= true then 28.14 + container_class = container_class .. " not_accepted" 28.15 +end 28.16 + 28.17 ui.container{ 28.18 - attr = { class = "member_thumb" }, 28.19 + attr = { class = container_class }, 28.20 content = function() 28.21 ui.container{ 28.22 attr = { class = "flags" }, 28.23 @@ -49,6 +55,13 @@ 28.24 else 28.25 slot.put(" ") 28.26 end 28.27 + if initiator and initiator.accepted then 28.28 + if member.accepted == nil then 28.29 + slot.put(_"Invited") 28.30 + elseif member.accepted == false then 28.31 + slot.put(_"Rejected") 28.32 + end 28.33 + end 28.34 if member.grade then 28.35 ui.container{ 28.36 content = function()
29.1 --- a/app/main/member/_show_thumb.lua.orig Mon Jan 04 12:00:00 2010 +0100 29.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 29.3 @@ -1,86 +0,0 @@ 29.4 -local member = param.get("member", "table") 29.5 - 29.6 -local issue = param.get("issue", "table") 29.7 -local initiative = param.get("initiative", "table") 29.8 -local trustee = param.get("trustee", "table") 29.9 - 29.10 -local name 29.11 -if member.name_highlighted then 29.12 - name = encode.highlight(member.name_highlighted) 29.13 -else 29.14 - name = encode.html(member.name) 29.15 -end 29.16 - 29.17 -ui.container{ 29.18 - attr = { class = "member_thumb" }, 29.19 - content = function() 29.20 - ui.container{ 29.21 - attr = { class = "flags" }, 29.22 - content = function() 29.23 - if (issue or initiative) and member.weight > 1 then 29.24 - local module 29.25 - if issue then 29.26 - module = "interest" 29.27 - elseif initiative then 29.28 - module = "supporter" 29.29 - end 29.30 - ui.link{ 29.31 - attr = { title = _"Number of incoming delegations, follow link to see more details" }, 29.32 - content = _("+ #{weight}", { weight = member.weight - 1 }), 29.33 - module = module, 29.34 - view = "show_incoming", 29.35 - params = { 29.36 - member_id = member.id, 29.37 - initiative_id = initiative and initiative.id or nil, 29.38 - issue_id = issue and issue.id or nil 29.39 - } 29.40 - } 29.41 - end 29.42 - -- TODO performance 29.43 - local contact = Contact:by_pk(app.session.member.id, member.id) 29.44 - if contact then 29.45 - ui.image{ 29.46 - attr = { 29.47 - alt = _"You have saved this member as contact", 29.48 - title = _"You have saved this member as contact" 29.49 - }, 29.50 - static = "icons/16/bullet_disk.png" 29.51 - } 29.52 - end 29.53 - end 29.54 - } 29.55 - 29.56 - ui.link{ 29.57 - attr = { title = _"Show member" }, 29.58 - module = "member", 29.59 - view = "show", 29.60 - id = member.id, 29.61 - content = function() 29.62 - execute.view{ 29.63 - module = "member_image", 29.64 - view = "_show", 29.65 - params = { 29.66 - member = member, 29.67 - image_type = "avatar", 29.68 - show_dummy = true 29.69 - } 29.70 - } 29.71 - end 29.72 - } 29.73 - 29.74 - ui.link{ 29.75 - attr = { title = _"Show member" }, 29.76 - module = "member", 29.77 - view = "show", 29.78 - id = member.id, 29.79 - content = function() 29.80 - ui.container{ 29.81 - attr = { class = "member_name" }, 29.82 - content = function() 29.83 - slot.put(name) 29.84 - end 29.85 - } 29.86 - end 29.87 - } 29.88 - end 29.89 -}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/app/main/member/developer_settings.lua Sun Jan 10 12:00:00 2010 +0100 30.3 @@ -0,0 +1,36 @@ 30.4 +slot.put_into("title", _"Developer features") 30.5 + 30.6 +slot.select("actions", function() 30.7 + ui.link{ 30.8 + content = function() 30.9 + ui.image{ static = "icons/16/cancel.png" } 30.10 + slot.put(_"Cancel") 30.11 + end, 30.12 + module = "member", 30.13 + view = "settings" 30.14 + } 30.15 +end) 30.16 + 30.17 +ui.form{ 30.18 + attr = { class = "vertical" }, 30.19 + module = "member", 30.20 + action = "update_stylesheet_url", 30.21 + routing = { 30.22 + ok = { 30.23 + mode = "redirect", 30.24 + module = "index", 30.25 + view = "index" 30.26 + } 30.27 + }, 30.28 + content = function() 30.29 + local setting_key = "liquidfeedback_frontend_stylesheet_url" 30.30 + local setting = Setting:by_pk(app.session.member.id, setting_key) 30.31 + local value = setting and setting.value 30.32 + ui.field.text{ 30.33 + label = _"Stylesheet URL", 30.34 + name = "stylesheet_url", 30.35 + value = value 30.36 + } 30.37 + ui.submit{ value = _"Set URL" } 30.38 + end 30.39 +}
31.1 --- a/app/main/member/list.lua Mon Jan 04 12:00:00 2010 +0100 31.2 +++ b/app/main/member/list.lua Sun Jan 10 12:00:00 2010 +0100 31.3 @@ -5,5 +5,5 @@ 31.4 execute.view{ 31.5 module = "member", 31.6 view = "_list", 31.7 - params = { members_selector = Member:new_selector():add_order_by("name") } 31.8 + params = { members_selector = Member:new_selector() } 31.9 }
32.1 --- a/app/main/member/settings.lua Mon Jan 04 12:00:00 2010 +0100 32.2 +++ b/app/main/member/settings.lua Sun Jan 10 12:00:00 2010 +0100 32.3 @@ -10,6 +10,20 @@ 32.4 module = "index", 32.5 view = "index" 32.6 } 32.7 + 32.8 + local setting_key = "liquidfeedback_frontend_developer_features" 32.9 + local setting = Setting:by_pk(app.session.member.id, setting_key) 32.10 + 32.11 + if setting then 32.12 + ui.link{ 32.13 + content = function() 32.14 + ui.image{ static = "icons/16/wrench.png" } 32.15 + slot.put(_"Developer features") 32.16 + end, 32.17 + module = "member", 32.18 + view = "developer_settings" 32.19 + } 32.20 + end 32.21 end) 32.22 32.23 ui.heading{ content = _"Change your name" } 32.24 @@ -72,4 +86,4 @@ 32.25 ui.field.password{ label = _"Repeat new password", name = "new_password2" } 32.26 ui.submit{ value = _"Change password" } 32.27 end 32.28 -} 32.29 +} 32.30 \ No newline at end of file
33.1 --- a/app/main/supporter/_show_box.lua Mon Jan 04 12:00:00 2010 +0100 33.2 +++ b/app/main/supporter/_show_box.lua Sun Jan 10 12:00:00 2010 +0100 33.3 @@ -3,103 +3,101 @@ 33.4 local initiative = param.get("initiative", "table") 33.5 local supporter = Supporter:by_pk(initiative.id, app.session.member.id) 33.6 33.7 - ui.container{ 33.8 - attr = { class = "actions" }, 33.9 - content = function() 33.10 - if not initiative.issue.fully_frozen and not initiative.issue.closed then 33.11 - if supporter then 33.12 - if not supporter:has_critical_opinion() then 33.13 - ui.container{ 33.14 - attr = { 33.15 - class = "head head_supporter", 33.16 - style = "cursor: pointer;", 33.17 - onclick = "document.getElementById('support_content').style.display = 'block';" 33.18 - }, 33.19 - content = function() 33.20 - ui.image{ 33.21 - static = "icons/16/thumb_up_green.png" 33.22 - } 33.23 - slot.put(_"Your are supporter") 33.24 - ui.image{ 33.25 - static = "icons/16/dropdown.png" 33.26 - } 33.27 - end 33.28 + if not initiative.issue.fully_frozen and not initiative.issue.closed then 33.29 + if supporter then 33.30 + if not supporter:has_critical_opinion() then 33.31 + ui.container{ 33.32 + attr = { 33.33 + class = "head head_supporter", 33.34 + style = "cursor: pointer;", 33.35 + onclick = "document.getElementById('support_content').style.display = 'block';" 33.36 + }, 33.37 + content = function() 33.38 + ui.image{ 33.39 + static = "icons/16/thumb_up_green.png" 33.40 + } 33.41 + slot.put(_"Your are supporter") 33.42 + ui.image{ 33.43 + static = "icons/16/dropdown.png" 33.44 } 33.45 - else 33.46 - ui.container{ 33.47 - attr = { 33.48 - class = "head head_potential_supporter", 33.49 - style = "cursor: pointer;", 33.50 - onclick = "document.getElementById('support_content').style.display = 'block';" 33.51 - }, 33.52 - content = function() 33.53 - ui.image{ 33.54 - static = "icons/16/thumb_up.png" 33.55 - } 33.56 - slot.put(_"Your are potential supporter") 33.57 - ui.image{ 33.58 - static = "icons/16/dropdown.png" 33.59 - } 33.60 - end 33.61 + end 33.62 + } 33.63 + else 33.64 + ui.container{ 33.65 + attr = { 33.66 + class = "head head_potential_supporter", 33.67 + style = "cursor: pointer;", 33.68 + onclick = "document.getElementById('support_content').style.display = 'block';" 33.69 + }, 33.70 + content = function() 33.71 + ui.image{ 33.72 + static = "icons/16/thumb_up.png" 33.73 + } 33.74 + slot.put(_"Your are potential supporter") 33.75 + ui.image{ 33.76 + static = "icons/16/dropdown.png" 33.77 } 33.78 end 33.79 + } 33.80 + end 33.81 + ui.container{ 33.82 + attr = { class = "content", id = "support_content" }, 33.83 + content = function() 33.84 ui.container{ 33.85 - attr = { class = "content", id = "support_content" }, 33.86 + attr = { 33.87 + class = "close", 33.88 + style = "cursor: pointer;", 33.89 + onclick = "document.getElementById('support_content').style.display = 'none';" 33.90 + }, 33.91 content = function() 33.92 - ui.container{ 33.93 - attr = { 33.94 - class = "close", 33.95 - style = "cursor: pointer;", 33.96 - onclick = "document.getElementById('support_content').style.display = 'none';" 33.97 - }, 33.98 - content = function() 33.99 - ui.image{ static = "icons/16/cross.png" } 33.100 - end 33.101 - } 33.102 - if supporter then 33.103 - ui.link{ 33.104 - content = function() 33.105 - ui.image{ static = "icons/16/thumb_down_red.png" } 33.106 - slot.put(_"Remove my support from this initiative") 33.107 - end, 33.108 - module = "initiative", 33.109 - action = "remove_support", 33.110 - id = initiative.id, 33.111 - routing = { 33.112 - default = { 33.113 - mode = "redirect", 33.114 - module = request.get_module(), 33.115 - view = request.get_view(), 33.116 - id = param.get_id_cgi(), 33.117 - params = param.get_all_cgi() 33.118 - } 33.119 - } 33.120 - } 33.121 - else 33.122 - end 33.123 + ui.image{ static = "icons/16/cross.png" } 33.124 end 33.125 } 33.126 - else 33.127 - ui.link{ 33.128 - content = function() 33.129 - ui.image{ static = "icons/16/thumb_up_green.png" } 33.130 - slot.put(_"Support this initiative") 33.131 - end, 33.132 - module = "initiative", 33.133 - action = "add_support", 33.134 - id = initiative.id, 33.135 - routing = { 33.136 - default = { 33.137 - mode = "redirect", 33.138 - module = request.get_module(), 33.139 - view = request.get_view(), 33.140 - id = param.get_id_cgi(), 33.141 - params = param.get_all_cgi() 33.142 + if supporter then 33.143 + ui.link{ 33.144 + content = function() 33.145 + ui.image{ static = "icons/16/thumb_down_red.png" } 33.146 + slot.put(_"Remove my support from this initiative") 33.147 + end, 33.148 + module = "initiative", 33.149 + action = "remove_support", 33.150 + id = initiative.id, 33.151 + routing = { 33.152 + default = { 33.153 + mode = "redirect", 33.154 + module = request.get_module(), 33.155 + view = request.get_view(), 33.156 + id = param.get_id_cgi(), 33.157 + params = param.get_all_cgi() 33.158 + } 33.159 } 33.160 } 33.161 + else 33.162 + end 33.163 + end 33.164 + } 33.165 + else 33.166 + if not initiative.revoked then 33.167 + ui.link{ 33.168 + content = function() 33.169 + ui.image{ static = "icons/16/thumb_up_green.png" } 33.170 + slot.put(_"Support this initiative") 33.171 + end, 33.172 + module = "initiative", 33.173 + action = "add_support", 33.174 + id = initiative.id, 33.175 + routing = { 33.176 + default = { 33.177 + mode = "redirect", 33.178 + module = request.get_module(), 33.179 + view = request.get_view(), 33.180 + id = param.get_id_cgi(), 33.181 + params = param.get_all_cgi() 33.182 + } 33.183 } 33.184 - end 33.185 + } 33.186 end 33.187 end 33.188 - } 33.189 + end 33.190 + 33.191 end)
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/app/main/timeline/index.lua Sun Jan 10 12:00:00 2010 +0100 34.3 @@ -0,0 +1,151 @@ 34.4 + 34.5 +local function format_dow(dow) 34.6 + local dows = { 34.7 + _"Monday", 34.8 + _"Tuesday", 34.9 + _"Wednesday", 34.10 + _"Thursday", 34.11 + _"Friday", 34.12 + _"Saturday", 34.13 + _"Sunday" 34.14 + } 34.15 + return dows[dow+1] 34.16 +end 34.17 + 34.18 +slot.put_into("title", _"Global timeline") 34.19 + 34.20 + 34.21 +ui.form{ 34.22 + attr = { class = "vertical" }, 34.23 + module = "timeline", 34.24 + view = "index", 34.25 + method = "get", 34.26 + content = function() 34.27 + local tmp = db:query("select EXTRACT(DOW FROM date) as dow, date FROM (SELECT (now() - (to_char(days_before, '0') || ' days')::interval)::date as date from (select generate_series(0,7) as days_before) as series) as date; ") 34.28 + local today = tmp[1].date 34.29 + for i, record in ipairs(tmp) do 34.30 + local content 34.31 + if i == 1 then 34.32 + content = _"Today" 34.33 + elseif i == 2 then 34.34 + content = _"Yesterday" 34.35 + else 34.36 + content = format_dow(record.dow) 34.37 + end 34.38 + ui.link{ 34.39 + content = content, 34.40 + attr = { onclick = "el = document.getElementById('timeline_search_date'); el.value = '" .. tostring(record.date) .. "'; el.form.submit(); return(false);" }, 34.41 + module = "timeline", 34.42 + view = "index", 34.43 + params = { date = record.date } 34.44 + } 34.45 + slot.put(" ") 34.46 + end 34.47 + ui.field.hidden{ 34.48 + attr = { id = "timeline_search_date" }, 34.49 + name = "date", 34.50 + value = param.get("date") or today 34.51 + } 34.52 + ui.field.select{ 34.53 + attr = { onchange = "this.form.submit();" }, 34.54 + name = "per_page", 34.55 + label = _"Issues per page", 34.56 + foreign_records = { 34.57 + { id = "10", name = "10" }, 34.58 + { id = "25", name = "25" }, 34.59 + { id = "50", name = "50" }, 34.60 + { id = "100", name = "100" }, 34.61 + { id = "250", name = "250" }, 34.62 + { id = "all", name = _"All" }, 34.63 + }, 34.64 + foreign_id = "id", 34.65 + foreign_name = "name", 34.66 + value = param.get("per_page") 34.67 + } 34.68 + local initiatives_per_page = param.get("initiatives_per_page", atom.integer) or 3 34.69 + 34.70 + ui.field.select{ 34.71 + attr = { onchange = "this.form.submit();" }, 34.72 + name = "initiatives_per_page", 34.73 + label = _"Initiatives per page", 34.74 + foreign_records = { 34.75 + { id = 1, name = "1" }, 34.76 + { id = 3, name = "3" }, 34.77 + { id = 5, name = "5" }, 34.78 + { id = 10, name = "10" }, 34.79 + { id = 25, name = "25" }, 34.80 + { id = 50, name = "50" }, 34.81 + }, 34.82 + foreign_id = "id", 34.83 + foreign_name = "name", 34.84 + value = initiatives_per_page 34.85 + } 34.86 + end 34.87 +} 34.88 + 34.89 +local date = param.get("date") 34.90 +if not date then 34.91 + date = "today" 34.92 +end 34.93 +local issues_selector = db:new_selector() 34.94 +issues_selector._class = Issue 34.95 + 34.96 +issues_selector 34.97 + :add_field("*") 34.98 + :add_where{ "sort::date = ?", date } 34.99 + :add_from{ "($) as issue", { 34.100 + Issue:new_selector() 34.101 + :add_field("''", "old_state") 34.102 + :add_field("'new'", "new_state") 34.103 + :add_field("created", "sort") 34.104 + :union(Issue:new_selector() 34.105 + :add_field("'new'", "old_state") 34.106 + :add_field("'accepted'", "new_state") 34.107 + :add_field("accepted", "sort") 34.108 + :add_where("accepted NOTNULL") 34.109 + ):union(Issue:new_selector() 34.110 + :add_field("'accepted'", "old_state") 34.111 + :add_field("'frozen'", "new_state") 34.112 + :add_field("half_frozen", "sort") 34.113 + :add_where("half_frozen NOTNULL") 34.114 + ):union(Issue:new_selector() 34.115 + :add_field("'frozen'", "old_state") 34.116 + :add_field("'voting'", "new_state") 34.117 + :add_field("fully_frozen", "sort") 34.118 + :add_where("fully_frozen NOTNULL") 34.119 + ):union(Issue:new_selector() 34.120 + :add_field("'new'", "old_state") 34.121 + :add_field("'cancelled'", "new_state") 34.122 + :add_field("closed", "sort") 34.123 + :add_where("closed NOTNULL AND accepted ISNULL") 34.124 + ):union(Issue:new_selector() 34.125 + :add_field("'accepted'", "old_state") 34.126 + :add_field("'cancelled'", "new_state") 34.127 + :add_field("closed", "sort") 34.128 + :add_where("closed NOTNULL AND half_frozen ISNULL AND accepted NOTNULL") 34.129 + ):union(Issue:new_selector() 34.130 + :add_field("'frozen'", "old_state") 34.131 + :add_field("'cancelled'", "new_state") 34.132 + :add_field("closed", "sort") 34.133 + :add_where("closed NOTNULL AND fully_frozen ISNULL AND half_frozen NOTNULL") 34.134 + ):union(Issue:new_selector() 34.135 + :add_field("'voting'", "old_state") 34.136 + :add_field("'finished'", "new_state") 34.137 + :add_field("closed", "sort") 34.138 + :add_where("closed NOTNULL AND fully_frozen NOTNULL AND half_frozen ISNULL") 34.139 + ) 34.140 + } 34.141 +} 34.142 + 34.143 +execute.view{ 34.144 + module = "issue", 34.145 + view = "_list", 34.146 + params = { 34.147 + issues_selector = issues_selector, 34.148 + initiatives_per_page = param.get("initiatives_per_page", atom.number), 34.149 + initiatives_no_sort = true, 34.150 + no_filter = true, 34.151 + no_sort = true, 34.152 + per_page = param.get("per_page"), 34.153 + } 34.154 +}
35.1 --- a/config/default.lua Mon Jan 04 12:00:00 2010 +0100 35.2 +++ b/config/default.lua Sun Jan 10 12:00:00 2010 +0100 35.3 @@ -1,5 +1,5 @@ 35.4 config.app_name = "LiquidFeedback" 35.5 -config.app_version = "beta5" 35.6 +config.app_version = "beta6" 35.7 35.8 config.app_title = config.app_name .. " (" .. request.get_config_name() .. " environment)" 35.9
36.1 --- a/config/development.lua Mon Jan 04 12:00:00 2010 +0100 36.2 +++ b/config/development.lua Sun Jan 10 12:00:00 2010 +0100 36.3 @@ -9,3 +9,5 @@ 36.4 36.5 config.mail_from = "LiquidFeedback" 36.6 config.mail_reply_to = "liquid-support@localhost" 36.7 + 36.8 +config.issue_discussion_url_func = function(issue) return "http://example.com/issue_" .. tostring(issue.id) end 36.9 \ No newline at end of file
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/locale/help/initiative.add_initiator.de.txt Sun Jan 10 12:00:00 2010 +0100 37.3 @@ -0,0 +1,2 @@ 37.4 +=Initiator einladen= 37.5 +Hier kannst du eine Person aus deiner Kontaktliste zur gleichberechtigten Mitarbeit am Entwurf einladen. Der eingeladene muss die Einladung erst akzeptieren, bevor er als weiterer Initiator gilt (und angezeigt wird). **Vorsicht:** Alle Initiatoren haben die gleichen Rechte und können andere Initiatoren entfernen.
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/locale/help/initiative.remove_initiator.de.txt Sun Jan 10 12:00:00 2010 +0100 38.3 @@ -0,0 +1,2 @@ 38.4 +=Initiator entfernen= 38.5 +Du kannst dich oder einen anderen Initiator entfernen, sofern nach dem Entfernen noch mindestens ein Initiator existiert. Um die Initiative insgesamt aufzugeben, wähle bitte ,,Initiative zurückziehen''.
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/locale/help/initiative.revoke.de.txt Sun Jan 10 12:00:00 2010 +0100 39.3 @@ -0,0 +1,2 @@ 39.4 +=Initiative zurückziehen= 39.5 +Du kannst diese Initiative zurückziehen. Dies kann nicht rückgängig gemacht werden. Natürlich hast du jederzeit die Möglichkeit, eine neue Initiative zu starten. Den Unterstützern kannst du eine alternative Initiative empfehlen.
40.1 --- a/locale/help/initiative.show.de.txt Mon Jan 04 12:00:00 2010 +0100 40.2 +++ b/locale/help/initiative.show.de.txt Sun Jan 10 12:00:00 2010 +0100 40.3 @@ -2,9 +2,11 @@ 40.4 Während der Diskussionsphase kannst du diese Initiative unterstützen und gibst damit den Initiatoren eine wichtige Rückmeldung, inwieweit der aktuelle Entwurf auf Zustimmung stößt. Darüber hinaus kannst du durch Anregungen (Änderungsvorschläge) mitteilen, was noch verbessert werden kann bzw. unter welchen Bedingungen du dir eine Unterstützung vorstellen kannst. 40.5 40.6 Du kannst dich den Anregungen anderer Mitglieder anschließen (und damit das Gewicht dieser Anregungen erhöhen) und eigene (zusätzliche) Anregungen einbringen. Anregungen, die aus deiner Sicht unbedingt eingearbeitet werden müssen, damit du zustimmst, kennzeichnest du mit ,,muss'', wünschenswerte mit ,,soll''. Du kannst Anregungen auch kritisch gegenüber stehen und sie mit ,,soll nicht'' kennzeichnen. Eine Anregung, die bei Umsetzung zum Entzug deiner Zustimmung führen würde, kennzeichnest du mit ,,darf nicht''. 40.7 -=überarbeiteter Entwurf, Umsetzungsvermerk= 40.8 +=überarbeiteter Entwurf, Umsetzungsvermerkn= 40.9 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. 40.10 +=weitere Initiatoren einladen, Zurückziehen einer Initiative= 40.11 +Ein Initiator kann weitere Initiatoren einladen und verleiht ihnen damit gleiche Rechte für die Bearbeitung des Entwurfs. Jeder Initiator einer Initiative kann die Initiative zurückziehen und auf Wunsch den Unterstützern eine andere Initiative als Alternative empfehlen. 40.12 =wenn du nicht gehört wirst= 40.13 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. 40.14 =wenn du diese Initiative ablehnst= 40.15 -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. 40.16 +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. Sofern du nicht ohnehin schon Mitglied des Themenbereichs bist, kannst du durch eine Mitgliedschaft im Themenbereich oder durch Anmeldung von Interesse am Thema die den erforderlichen Unterstützerquorum zugrundeliegende Grundgesamtheit erhöhen. Den gleichen Effekt erreichst du auch, wenn du an ein Mitglied des Themenbereichs oder einen Interessenten am Thema delegierst. **Nur bei Status ,,Neu'':** Falls das Thema, zu dem diese Initiative gehört, noch im Zustand ,,Neu'' ist und du dieses Thema eigentlich gar nicht diskutieren möchtest, solltest du zunächst nur Mitglied des Themenbereichs werden oder Interesse am Thema anmelden und keine Anregungen eingeben, die dich zum (potentiellen) Unterstützer machen würden. Ebenso solltest du noch keine Gegeninitiative starten, die das Thema über die Zulassungshürde heben könnte.
41.1 --- a/locale/translations.de.lua Mon Jan 04 12:00:00 2010 +0100 41.2 +++ b/locale/translations.de.lua Sun Jan 10 12:00:00 2010 +0100 41.3 @@ -1,4 +1,4 @@ 41.4 --- #!/usr/bin/env lua 41.5 +#!/usr/bin/env lua 41.6 return { 41.7 ["#{interested_issues_to_vote_count} issue(s) you are interested in"] = "#{interested_issues_to_vote_count} Themen, die Dich interessieren"; 41.8 ["#{issues_to_vote_count} issue(s)"] = "#{issues_to_vote_count} Themen"; 41.9 @@ -11,6 +11,7 @@ 41.10 ["About"] = "About"; 41.11 ["About LiquidFeedback"] = "Über LiquidFeedback"; 41.12 ["Abstention"] = "Enthaltung"; 41.13 +["Accept invitation"] = "Einladung annehmen"; 41.14 ["Accepted at"] = "Angenommen am/um"; 41.15 ["Active?"] = "Aktiv?"; 41.16 ["Add my interest"] = "Mein Interesse anmelden"; 41.17 @@ -24,7 +25,9 @@ 41.18 ["Administrator"] = "Administrator"; 41.19 ["Admission time"] = "Zeit für die Zulassung"; 41.20 ["Admitted"] = "zugelassen"; 41.21 +["All"] = "Alle"; 41.22 ["Any"] = "Alle"; 41.23 +["Are you sure?"] = "Sicher?"; 41.24 ["Area"] = "Themenbereich"; 41.25 ["Area '#{name}'"] = "Themenbereich '#{name}'"; 41.26 ["Area delegation"] = "Area-Delegation"; 41.27 @@ -39,9 +42,11 @@ 41.28 ["Back"] = "Zurück"; 41.29 ["Become a member"] = "Mitglied werden"; 41.30 ["Birthday"] = "Geburtstag"; 41.31 +["Can't remove last initiator"] = "Der letzte Initiator kann nicht entfernt werden"; 41.32 ["Can't send confirmation email"] = "Bestätigungs-E-Mail kann nicht versendet werden."; 41.33 ["Cancel"] = "Abbrechen"; 41.34 ["Cancel password reset"] = "Kennwort-Rücksetzung abbrechen"; 41.35 +["Cancel refuse of invitation"] = "Ablehnung der Einladung aufheben"; 41.36 ["Cancel registration"] = "Registration abbrechen"; 41.37 ["Cancelled"] = "Abgebrochen"; 41.38 ["Change area delegation"] = "Delegation für Themengebiet ändern"; 41.39 @@ -53,6 +58,8 @@ 41.40 ["Change your login"] = "Deinen Anmeldenamen ändern"; 41.41 ["Change your name"] = "Deinen Namen ändern"; 41.42 ["Change your password"] = "Dein Kennwort ändern"; 41.43 +["Choose initiator"] = "Initiator auswählen"; 41.44 +["Choose member"] = "Mitglied auswählen"; 41.45 ["Click for details"] = "Klicke für Details"; 41.46 ["Close"] = "Schließen"; 41.47 ["Closed"] = "geschlossen"; 41.48 @@ -75,15 +82,19 @@ 41.49 ["Delegations"] = "Delegationen"; 41.50 ["Description"] = "Beschreibung"; 41.51 ["Details"] = "Details"; 41.52 +["Developer features"] = "Entwicklerfunktionen"; 41.53 ["Diff"] = "Differenz"; 41.54 ["Direct member count"] = "Anzahl Direktmitglieder"; 41.55 ["Direct membership"] = "Direkte Mitgliedschaft"; 41.56 ["Discussion"] = "Diskussion"; 41.57 ["Discussion URL"] = "Diskussions-URL"; 41.58 +["Discussion on issue"] = "Diskussion zum Thema"; 41.59 ["Discussion time"] = "Zeit für die Diskussions"; 41.60 +["Discussion with initiators"] = "Diskussion mit den Initiatoren"; 41.61 ["Download"] = "Download"; 41.62 ["Download database export"] = "Datenbankexport herunterladen"; 41.63 ["Draft"] = "Entwurf"; 41.64 +["Draft history"] = "Entwurfshistorie"; 41.65 ["Edit"] = "Bearbeiten"; 41.66 ["Edit draft"] = "Entwurf bearbeiten"; 41.67 ["Edit initiative"] = "Initiative bearbeiten"; 41.68 @@ -101,10 +112,12 @@ 41.69 ["Filter"] = "Filter"; 41.70 ["Finish voting"] = "Stimmabgabe abschließen"; 41.71 ["Finished"] = "Abgeschlossen"; 41.72 +["Friday"] = "Freitag"; 41.73 ["Frozen"] = "Eingefroren"; 41.74 ["Fully frozen at"] = "Ganz eingefroren am/um"; 41.75 ["Global delegation"] = "Globale Delegation"; 41.76 ["Global delegation active"] = "Globale Delegation aktiv"; 41.77 +["Global timeline"] = "Globale Zeitlinie"; 41.78 ["Half frozen at"] = "Halb eingefroren am/um"; 41.79 ["Hello "] = "Hallo "; 41.80 ["Help for: #{text}"] = "Hilfe zu: #{text}"; 41.81 @@ -119,11 +132,14 @@ 41.82 ["In discussion"] = "In Diskussion"; 41.83 ["Incoming delegations"] = "Eingehende Delegationen"; 41.84 ["Initiated initiatives"] = "Initierte Initiativen"; 41.85 +["Initiative is revoked now"] = "Initiative ist jetzt zurückgezogen"; 41.86 ["Initiative quorum"] = "Quorum Inititive"; 41.87 ["Initiative successfully created"] = "Initiative erfolgreich erzeugt"; 41.88 ["Initiative successfully updated"] = "Initiative erfolgreich aktualisiert"; 41.89 ["Initiative: '#{name}'"] = "Initiative: '#{name}'"; 41.90 ["Initiatives"] = "Initiativen"; 41.91 +["Initiatives per page"] = "Initiativen je Seite"; 41.92 +["Initiatives that invited you to become initiator:"] = "Initiative, die Dich eingeladen haben, Initiator zu werden:"; 41.93 ["Initiator"] = "Initiator"; 41.94 ["Initiators"] = "Initiatoren"; 41.95 ["Interest not existant"] = "Interesse existiert nicht"; 41.96 @@ -133,16 +149,23 @@ 41.97 ["Interested members"] = "Interessierte Mitglieder"; 41.98 ["Internal posts"] = "Interne Ämter"; 41.99 ["Invalid username or password!"] = "Ungültiger Benutzername oder Kennwort"; 41.100 +["Invitation has been refused"] = "Einladung wurde widerrufen"; 41.101 +["Invite an initiator to initiative"] = "Initiator zur Initiative einladen"; 41.102 ["Invite code"] = "Invite-Code"; 41.103 +["Invite initiator"] = "Initiator einladen"; 41.104 +["Invited"] = "Eingeladen"; 41.105 +["Inviting initiator"] = "Initiatoren einladen"; 41.106 ["Issue"] = "Thema"; 41.107 -["Issue ##{id}"] = "Issue ##{id}"; 41.108 +["Issue ##{id}"] = "Thema ##{id}"; 41.109 ["Issue ##{id} (#{policy_name})"] = "Thema ##{id} (#{policy_name})"; 41.110 ["Issue delegation"] = "Issue-Delegation"; 41.111 ["Issue delegation active"] = "Delegation für Thema aktiv"; 41.112 ["Issue policy"] = "Regelwerk für Thema"; 41.113 ["Issue quorum"] = "Quorum Thema"; 41.114 ["Issues"] = "Themen"; 41.115 +["Issues per page"] = "Themen je Seite"; 41.116 ["JavaScript is disabled or not available."] = "JavaScript ist abgeschaltet oder nicht verfügbar."; 41.117 +["Last author"] = "Letzter Autor"; 41.118 ["Last snapshot:"] = "Letzte Auszählung:"; 41.119 ["Legend:"] = "Legende:"; 41.120 ["License"] = "Lizenz"; 41.121 @@ -158,10 +181,13 @@ 41.122 ["Mark suggestion as not implemented and express satisfaction"] = "Anregung als nicht umgesetzt markieren und Zufriedenheit ausdrücken"; 41.123 ["Max potential support"] = "Max. potentielle Unterstützer"; 41.124 ["Max support"] = "Max. Unterstützer"; 41.125 +["Member"] = "Mitglied"; 41.126 ["Member '#{member}'"] = "Mitglied '#{member}'"; 41.127 +["Member has been removed from initiators"] = "Mitglied wurde von den Initiatoren entfernt"; 41.128 ["Member has been removed from your contacts"] = "Mitglied wurde aus Deinen Kontakten entfernt"; 41.129 ["Member is administrator"] = "Mitglied ist Administrator"; 41.130 ["Member is already saved in your contacts!"] = "Mitglied ist schon in Deinen Kontakten!"; 41.131 +["Member is now invited to be initiator"] = "Mitglied ist jetzt als Initiator eingeladen"; 41.132 ["Member list"] = "Mitgliederliste"; 41.133 ["Member name"] = "Mitglied Name"; 41.134 ["Member name history for '#{name}'"] = "Namenshistorie für '#{name}'"; 41.135 @@ -177,6 +203,7 @@ 41.136 ["Memberships"] = "Mitgliedschaften"; 41.137 ["Missing help text: #{id}.#{lang}.txt"] = "Fehlender Hilfe-Text: #{id}.#{lang}.txt"; 41.138 ["Mobile phone"] = "Mobiltelefon"; 41.139 +["Monday"] = "Montag"; 41.140 ["My opinion"] = "Meine Meinung"; 41.141 ["Name"] = "Name"; 41.142 ["New"] = "Neu"; 41.143 @@ -198,7 +225,6 @@ 41.144 ["Number of incoming delegations, follow link to see more details"] = "Anzahl eingehender Delegationen, Link folgen für mehr Details"; 41.145 ["OK"] = "OK"; 41.146 ["Old draft revision"] = "Alte Revision des Entwurfs"; 41.147 -["Old drafts"] = "Alte Entwürfe"; 41.148 ["Old password"] = "Altes Kennwort"; 41.149 ["Old password is wrong"] = "Das alte Kennwort ist falsch"; 41.150 ["Oldest"] = "Älteste"; 41.151 @@ -220,8 +246,12 @@ 41.152 ["Phone"] = "Telefon"; 41.153 ["Photo"] = "Foto"; 41.154 ["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."; 41.155 +["Please choose a member"] = "Bitte wähle ein Mitglied"; 41.156 ["Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you."] = "Wähle einen Namen, z. B. Deinen Real- oder Nicknamen. Dieser wird anderen angezeigt um Dich zu identifizieren."; 41.157 ["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."; 41.158 +["Please choose a policy"] = "Bitte wähle ein Regelwerk"; 41.159 +["Please choose two different versions of the draft to compare"] = "Bitte wähle zwei verschiedene Versionen des Drafts, um sie zu vergleichen."; 41.160 +["Please choose two versions of the draft to compare"] = "Bitte wähle zwei Versionen des Drafts, um sie zu vergleichen."; 41.161 ["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"; 41.162 ["Please enter the email reset code you have received:"] = "Bitte gib den Rücksetzcode ein, den Du erhalten hast:"; 41.163 ["Please enter the invite code you've received."] = "Bitte gib den Invite-Code ein, den Du erhalten hast."; 41.164 @@ -241,12 +271,16 @@ 41.165 ["Rank"] = "Rang"; 41.166 ["Real name"] = "Realname"; 41.167 ["Refresh support to current draft"] = "Unterstützung auf aktuellen Entwurf aktualisieren"; 41.168 +["Refuse invitation"] = "Einladung ablehnen"; 41.169 ["Register"] = "Registrieren"; 41.170 ["Register new member"] = "Neues Mitglied registrieren"; 41.171 ["Registration"] = "Registrierung"; 41.172 +["Rejected"] = "Abgelehnt"; 41.173 ["Remove"] = "Entfernen"; 41.174 ["Remove autoreject"] = "Auto-Ablehnen abschalten"; 41.175 ["Remove from contacts"] = "Aus den Kontakten entfernen"; 41.176 +["Remove initiator"] = "Initiator entfernen"; 41.177 +["Remove initiator from initiative"] = "Initiator von der Initiative entfernen"; 41.178 ["Remove my interest"] = "Interesse abmelden"; 41.179 ["Remove my membership"] = "Mitgliedschaft aufgeben"; 41.180 ["Remove my support from this initiative"] = "Meine Unterstützung der Initiative entziehen"; 41.181 @@ -257,7 +291,9 @@ 41.182 ["Reset link has been send for this member"] = "Rücksetz-Link wurde versendet"; 41.183 ["Reset password"] = "Kennwort zurücksetzen"; 41.184 ["Revoke"] = "Widerrufen"; 41.185 +["Revoke initiative"] = "Initiative zurückziehen"; 41.186 ["Revoked at"] = "Zurückgezogen am/um"; 41.187 +["Saturday"] = "Samstag"; 41.188 ["Save"] = "Speichern"; 41.189 ["Saved as contact"] = "Als Kontakt speichern"; 41.190 ["Search"] = "Suchen"; 41.191 @@ -265,6 +301,7 @@ 41.192 ["Search issues"] = "Suche Themen"; 41.193 ["Search members"] = "Suche Mitglieder"; 41.194 ["Search results for: '#{search}'"] = "Suchergebnisse für: '#{search}'"; 41.195 +["Set URL"] = "URL setzen"; 41.196 ["Set area delegation"] = "Delegation für Themengebiet festlegen"; 41.197 ["Set autoreject"] = "Auto-Ablehnen anschalten"; 41.198 ["Set delegation for Area '#{name}'"] = "Delegation für Themengebiet '#{name}' festlegen"; 41.199 @@ -285,6 +322,7 @@ 41.200 ["Software"] = "Software"; 41.201 ["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."; 41.202 ["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."; 41.203 +["Sorry, but you are currently not invited"] = "Sorry, aber Du bist zur Zeit nicht eingeladen"; 41.204 ["Sorry, you have reached your personal flood limit. Please be slower..."] = "Sorry, Du hast Dein persönliches Flood-Limit erreicht. Bitte sei langsamer..."; 41.205 ["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!"; 41.206 ["State"] = "Zustand"; 41.207 @@ -294,11 +332,16 @@ 41.208 ["Step 3/5: Username"] = "Schritt 3/5: Benutzername"; 41.209 ["Step 4/5: Login name"] = "Schritt 4/5: Anmeldename"; 41.210 ["Step 5/5: Terms of use and password"] = "Schritt 5/5: Nutzungsbedingungen und Kennwort"; 41.211 +["Stylesheet URL"] = "Stylesheet URL"; 41.212 +["Stylesheet URL has been updated"] = "Stylesheet URL wurde aktualisiert"; 41.213 +["Suggest no initiative"] = "Keine Initiative empfehlen"; 41.214 +["Suggested initiative"] = "Empfohlene Initiative"; 41.215 ["Suggestion"] = "Anregung"; 41.216 ["Suggestion currently implemented"] = "Anregung zur Zeit umgesetzt"; 41.217 ["Suggestion currently not implemented"] = "Anregung zur Zeit nicht umgesetzt"; 41.218 ["Suggestion for initiative: '#{name}'"] = "Anregung für Initiative '#{name}'"; 41.219 ["Suggestions"] = "Anregungen"; 41.220 +["Sunday"] = "Sonntag"; 41.221 ["Support"] = "Unterstützung"; 41.222 ["Support this initiative"] = "Diese Initiative unterstützen"; 41.223 ["Supported initiatives"] = "Unterstützte Initiativen"; 41.224 @@ -306,21 +349,31 @@ 41.225 ["Terms accepted"] = "Bedingungen akzeptiert"; 41.226 ["The code you've entered is invalid"] = "Der Code, den Du eingeben hast, ist nicht gültig!"; 41.227 ["The drafts do not differ"] = "Die Entwürfe unterscheiden sich nicht"; 41.228 +["The initiators suggest to support the following initiative:"] = "Die Initiatoren empfehlen folgende Initiative zu unterstützen:"; 41.229 +["This initiative has been revoked at #{revoked}"] = "Diese Initiative wurde am/um #{revoked} zurückgezogen"; 41.230 +["This initiative is already revoked"] = "Diese Initiative ist schon zurückgezogen"; 41.231 +["This initiative is revoked"] = "Diese Initiative wurde zurückgezogen"; 41.232 ["This issue is already closed."] = "Das Thema ist schon geschlossen."; 41.233 ["This issue is already frozen."] = "Das Thema ist schon eingefroren"; 41.234 ["This login is already taken, please choose another one!"] = "Dieser Anmeldename ist bereits vergeben, bitte wähle einen anderen!"; 41.235 ["This login is too short!"] = "Dieser Anmeldename ist zu kurz!"; 41.236 ["This member account has been created at #{created}"] = "Dieser Mitgliedszugang wurde am/um #{created} angelegt."; 41.237 +["This member has rejected to become initiator of this initiative"] = "Dieses Mitglied hat die Einladung, Initiator zu werden, abgelehnt"; 41.238 +["This member is already initiator of this initiative"] = "Dieses Mitglied ist bereits Initiator dieser Initiative"; 41.239 +["This member is already invited to become initiator of this initiative"] = "Dieses Mitglied ist bereits eingeladen Initiator dieser Initiative zu werden"; 41.240 ["This name is already taken, please choose another one!"] = "Dieser Name ist bereits vergeben, bitte wähle einen anderen!"; 41.241 ["This name is really too short!"] = "Dieser Name ist wirklich zu kurz!"; 41.242 ["This name is too short!"] = "Dieser Name ist zu kurz!"; 41.243 ["This suggestion has been meanwhile deleted"] = "Diese Anregung wurde zwischenzeitlich gelöscht"; 41.244 ["This title is really too short!"] = "Dieser Titel ist wirklich zu kurz!"; 41.245 ["This username is too short!"] = "Dieser Benutzername ist zu kurz!"; 41.246 +["Thursday"] = "Donnerstag"; 41.247 ["Time left"] = "Restzeit"; 41.248 ["Title (80 chars max)"] = "Title (max. 80 Zeichen)"; 41.249 +["Today"] = "Heute"; 41.250 ["Traditional wiki syntax"] = "Traditionaller Wiki-Syntax"; 41.251 ["Trustee"] = "Bevollmächtigter"; 41.252 +["Tuesday"] = "Dienstag"; 41.253 ["Unknown author"] = "Unbekannter Autor"; 41.254 ["Upload images"] = "Bilder hochladen"; 41.255 ["Used until"] = "Benutzt bis"; 41.256 @@ -342,16 +395,23 @@ 41.257 ["Voting requests"] = "Abstimmanträge"; 41.258 ["Voting time"] = "Zeit für die Abstimmung"; 41.259 ["Website"] = "Webseite"; 41.260 +["Wednesday"] = "Mittwoch"; 41.261 ["Wiki engine"] = "Wiki engine"; 41.262 ["Yes"] = "Ja"; 41.263 +["Yesterday"] = "Gestern"; 41.264 +["You are already initator"] = "Du bist bereits Initiator"; 41.265 ["You are already not supporting this initiative"] = "Diese Initiative hat bereits keine Unterstützung von Dir"; 41.266 ["You are already supporting the latest draft"] = "Du unterstützt bereits den neuesten Entwurf"; 41.267 ["You are currently not supporting this initiative. By adding suggestions to this initiative you will automatically become a potential supporter."] = "Du bist zur Zeit kein Unterstützer dieser Initiative. Wenn Du eine Anregung hinzufügst wirst Du automatisch potentieller Unterstützer!"; 41.268 +["You are invited to become initiator of this initiative."] = "Du bist eingeladen Initiator dieser Initiative zu werden."; 41.269 ["You are member"] = "Du bist Mitglied"; 41.270 +["You are now initiator of this initiative"] = "Du bist jetzt Initiator dieser Initiative"; 41.271 +["You can't suggest the initiative you are revoking"] = "Du kannst nicht die Initiative empfehlen, die Du löschen möchtest"; 41.272 ["You didn't saved any member as contact yet."] = "Du hast noch kein Mitglied als Kontakt gespeichert!"; 41.273 ["You have saved this member as contact"] = "Du hast das Mitglied als Kontakt gespeichert"; 41.274 ["You have saved this member as contact."] = "Du hast das Mitglied als Kontakt gespeichert."; 41.275 ["You have to accept the terms of use to complete registration."] = "Du musst die Nutzungsbedingungen akzeptieren um die Registration abzuschliessen."; 41.276 +["You have to mark 'Are you sure' to revoke!"] = "Zum Zurückziehen musst Du 'Sicher?' auswählen"; 41.277 ["You need to be logged in, to use this system."] = "Du musst eingeloggt sein, um das System zu benutzen"; 41.278 ["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!"; 41.279 ["Your are interested"] = "Du bist interessiert";
42.1 --- a/model/area.lua Mon Jan 04 12:00:00 2010 +0100 42.2 +++ b/model/area.lua Sun Jan 10 12:00:00 2010 +0100 42.3 @@ -54,7 +54,7 @@ 42.4 return Policy:new_selector() 42.5 :join("allowed_policy", nil, "allowed_policy.policy_id = policy.id") 42.6 :add_where{ "allowed_policy.area_id = ? AND allowed_policy.default_policy", self.id } 42.7 - :single_object_mode() 42.8 + :optional_object_mode() 42.9 :exec() 42.10 end 42.11
43.1 --- a/model/initiative.lua Mon Jan 04 12:00:00 2010 +0100 43.2 +++ b/model/initiative.lua Sun Jan 10 12:00:00 2010 +0100 43.3 @@ -34,8 +34,7 @@ 43.4 this_key = 'id', 43.5 that_key = 'initiative_id', 43.6 ref = 'initiators', 43.7 - back_ref = 'initiative', 43.8 - default_order = '"id"' 43.9 + back_ref = 'initiative' 43.10 } 43.11 43.12 Initiative:add_reference{ 43.13 @@ -69,6 +68,14 @@ 43.14 } 43.15 43.16 Initiative:add_reference{ 43.17 + mode = 'm1', 43.18 + to = "Initiative", 43.19 + this_key = 'suggested_initiative_id', 43.20 + that_key = 'id', 43.21 + ref = 'suggested_initiative', 43.22 +} 43.23 + 43.24 +Initiative:add_reference{ 43.25 mode = 'mm', 43.26 to = "Member", 43.27 this_key = 'id',
44.1 --- a/model/issue.lua Mon Jan 04 12:00:00 2010 +0100 44.2 +++ b/model/issue.lua Sun Jan 10 12:00:00 2010 +0100 44.3 @@ -119,7 +119,7 @@ 44.4 finished = _"Finished", 44.5 cancelled = _"Cancelled" 44.6 } 44.7 - return state_name_table[value] or value 44.8 + return state_name_table[value] or value or '' 44.9 end 44.10 44.11 function Issue:get_search_selector(search_string)
45.1 --- a/model/member.lua Mon Jan 04 12:00:00 2010 +0100 45.2 +++ b/model/member.lua Sun Jan 10 12:00:00 2010 +0100 45.3 @@ -95,8 +95,7 @@ 45.4 this_key = 'id', 45.5 that_key = 'member_id', 45.6 ref = 'initiators', 45.7 - back_ref = 'member', 45.8 - default_order = '"id"' 45.9 + back_ref = 'member' 45.10 } 45.11 45.12 Member:add_reference{
46.1 Binary file static/icons/16/script_delete.png has changed
47.1 Binary file static/icons/16/user_delete.png has changed
48.1 --- a/static/style.css Mon Jan 04 12:00:00 2010 +0100 48.2 +++ b/static/style.css Sun Jan 10 12:00:00 2010 +0100 48.3 @@ -40,6 +40,10 @@ 48.4 color: #fff; 48.5 } 48.6 48.7 +.revoked { 48.8 + text-decoration: line-through; 48.9 +} 48.10 + 48.11 .highlighted { 48.12 background-color: #fa7; 48.13 color: #000; 48.14 @@ -62,7 +66,6 @@ 48.15 } 48.16 48.17 48.18 - 48.19 /************************************************************************* 48.20 * Notices, warnings and errors 48.21 */ 48.22 @@ -274,7 +277,7 @@ 48.23 } 48.24 48.25 .interest .head_active, 48.26 -.slot_support .head_potential_supporter { 48.27 +.slot_support .head_potential_supporter{ 48.28 background-color: #fec; 48.29 border: 1px solid #b96; 48.30 } 48.31 @@ -284,6 +287,11 @@ 48.32 border: 1px solid #8b8; 48.33 } 48.34 48.35 +.slot_support .head_initiator { 48.36 + background-color: #eee; 48.37 + border: 1px solid #999; 48.38 +} 48.39 + 48.40 .delegation .head_active { 48.41 background-color: #ddf; 48.42 border: 1px solid #88b; 48.43 @@ -759,6 +767,10 @@ 48.44 float: right; 48.45 } 48.46 48.47 +.member_thumb.not_accepted { 48.48 + opacity: 0.5; 48.49 +} 48.50 + 48.51 .draft_content, 48.52 .member_statement { 48.53 background-color: #eee; 48.54 @@ -803,7 +815,9 @@ 48.55 } 48.56 48.57 .draft_updated_info, 48.58 -.voting_active_info { 48.59 +.voting_active_info, 48.60 +.revoked_info, 48.61 +.initiator_invite_info { 48.62 background-color: #fec; 48.63 border: 2px solid #b96; 48.64 padding: 1ex;