") - ui.tag{ - tag = "div", + if not config.locked_profile_fields.notify_email then + ui.tag{ + tag = "p", + content = _"Please enter your email address. This address will be used for automatic notifications (if you request them) and in case you've lost your password. This address will not be published. After registration you will receive an email with a confirmation link." + } + ui.field.text{ + label = _'Email address', + name = 'notify_email', + value = param.get("notify_email") or member.notify_email + } + end + if not config.locked_profile_fields.name then + ui.tag{ + tag = "p", + content = _"Please choose a name, i.e. your real name or your nick name. This name will be shown to others to identify you." + } + ui.field.text{ + label = _'Screen name', + name = 'name', + value = param.get("name") or member.name + } + end + if not config.locked_profile_fields.login then + ui.tag{ + tag = "p", + content = _"Please choose a login name. This name will not be shown to others and is used only by you to login into the system. The login name is case sensitive." + } + ui.field.text{ + label = _'Login name', + name = 'login', + value = param.get("login") or member.login + } + end + else + + ui.field.hidden{ name = "step", value = "3" } + slot.put_into("title", _"Step 3/3: Terms of use and password") + slot.select("actions", function() + ui.link{ + content = function() + ui.image{ static = "icons/16/resultset_previous.png" } + slot.put(_"One step back") + end, + module = "index", + view = "register", + params = { + code = code, + notify_email = notify_email, + name = name, + login = login, + step = 1 + } + } + end) + ui.container{ + attr = { class = "wiki use_terms" }, content = function() - ui.tag{ - tag = "input", - attr = { - type = "checkbox", - name = "use_terms_checkbox_" .. checkbox.name, - value = "1", - style = "float: left;", - checked = param.get("use_terms_checkbox_" .. checkbox.name, atom.boolean) and "checked" or nil - } - } - slot.put(" ") - slot.put(checkbox.html) + if config.use_terms_html then + slot.put(config.use_terms_html) + else + slot.put(format.wiki_text(config.use_terms)) + end end } - end - slot.put("
") + for i, checkbox in ipairs(config.use_terms_checkboxes) do + slot.put("
") + ui.tag{ + tag = "div", + content = function() + ui.tag{ + tag = "input", + attr = { + type = "checkbox", + name = "use_terms_checkbox_" .. checkbox.name, + value = "1", + style = "float: left;", + checked = param.get("use_terms_checkbox_" .. checkbox.name, atom.boolean) and "checked" or nil + } + } + slot.put(" ") + slot.put(checkbox.html) + end + } + end - ui.field.text{ - label = _'Email address', - value = param.get("notify_email"), - readonly = true - } - ui.field.text{ - label = _'Name', - value = param.get("name"), - readonly = true - } - ui.field.text{ - label = _'Login name', - value = param.get("login"), - readonly = true - } + slot.put("
") - ui.tag{ - tag = "p", - content = _"Please choose a password and enter it twice. The password is case sensitive." - } - ui.field.password{ - label = _'Password', - name = 'password1', - } - ui.field.password{ - label = _'Password (repeat)', - name = 'password2', - } + member.notify_email = notify_email or member.notify_email + member.name = name or member.name + member.login = login or member.login + + execute.view{ module = "member", view = "_profile", params = { + member = member, include_private_data = true + } } + + ui.tag{ + tag = "p", + content = _"Please choose a password and enter it twice. The password is case sensitive." + } + ui.field.password{ + label = _'Password', + name = 'password1', + } + ui.field.password{ + label = _'Password (repeat)', + name = 'password2', + } + end end - ui.submit{ - text = _'Register' - } + ui.submit{ + text = _'Register' + } - slot.put_into("title", ")") - slot.select("actions", function() - ui.link{ - content = function() - ui.image{ static = "icons/16/cancel.png" } - slot.put(_"Cancel registration") - end, - module = "index", - view = "index" - } - end) - + slot.put_into("title", ")") + slot.select("actions", function() + ui.link{ + content = function() + ui.image{ static = "icons/16/cancel.png" } + slot.put(_"Cancel registration") + end, + module = "index", + view = "index" + } + end) end } diff -r 6c88b4bfb56c -r c587d8762e62 app/main/initiative/_action/create.lua --- a/app/main/initiative/_action/create.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/initiative/_action/create.lua Sat Feb 25 11:51:37 2012 +0100 @@ -87,6 +87,16 @@ issue.area_id = area.id issue.policy_id = policy_id issue:save() + + if config.etherpad then + local result = net.curl( + config.etherpad.api_base + .. "api/1/createGroupPad?apikey=" .. config.etherpad.api_key + .. "&groupID=" .. config.etherpad.group_id + .. "&padName=Issue" .. tostring(issue.id) + .. "&text=" .. config.absolute_base_url .. "issue/show/" .. tostring(issue.id) .. ".html" + ) + end end initiative.issue_id = issue.id diff -r 6c88b4bfb56c -r c587d8762e62 app/main/initiative/_show.lua --- a/app/main/initiative/_show.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/initiative/_show.lua Sat Feb 25 11:51:37 2012 +0100 @@ -32,87 +32,86 @@ attr = { class = "initiative_name" }, content = _("Initiative i#{id}: #{name}", { id = initiative.id, name = initiative.name }) } - if app.session.member_id or config.public_access == "pseudonym" or config.public_access == "full" then - ui.tag{ - attr = { class = "initiator_names" }, - content = function() - for i, initiator in ipairs(initiators) do - slot.put(" ") - ui.link{ - content = function () - execute.view{ - module = "member_image", - view = "_show", - params = { - member = initiator, - image_type = "avatar", - show_dummy = true, - class = "micro_avatar", - popup_text = text - } +end ) + +if app.session.member_id or config.public_access == "pseudonym" or config.public_access == "full" then + ui.tag{ + attr = { class = "initiator_names" }, + content = function() + for i, initiator in ipairs(initiators) do + slot.put(" ") + ui.link{ + content = function () + execute.view{ + module = "member_image", + view = "_show", + params = { + member = initiator, + image_type = "avatar", + show_dummy = true, + class = "micro_avatar", + popup_text = text } - end, - module = "member", view = "show", id = initiator.id - } - slot.put(" ") - ui.link{ - text = initiator.name, - module = "member", view = "show", id = initiator.id - } - if not initiator.accepted then - ui.tag{ attr = { title = _"Not accepted yet" }, content = "?" } - end + } + end, + module = "member", view = "show", id = initiator.id + } + slot.put(" ") + ui.link{ + text = initiator.name, + module = "member", view = "show", id = initiator.id + } + if not initiator.accepted then + ui.tag{ attr = { title = _"Not accepted yet" }, content = "?" } end end - } - end + end + } +end - if initiator and initiator.accepted and not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then +if initiator and initiator.accepted and not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then + slot.put(" · ") + ui.link{ + attr = { class = "action" }, + content = function() + slot.put(_"Invite initiator") + end, + module = "initiative", + view = "add_initiator", + params = { initiative_id = initiative.id } + } + if #initiators > 1 then slot.put(" · ") ui.link{ - attr = { class = "action" }, content = function() - slot.put(_"Invite initiator") + slot.put(_"Remove initiator") end, module = "initiative", - view = "add_initiator", + view = "remove_initiator", params = { initiative_id = initiative.id } } - if #initiators > 1 then - slot.put(" · ") - ui.link{ - content = function() - slot.put(_"Remove initiator") - end, - module = "initiative", - view = "remove_initiator", - params = { initiative_id = initiative.id } - } - end end - if initiator and initiator.accepted == false then - slot.put(" · ") - ui.link{ - text = _"Cancel refuse of invitation", - module = "initiative", - action = "remove_initiator", - params = { - initiative_id = initiative.id, - member_id = app.session.member.id - }, - routing = { - ok = { - mode = "redirect", - module = "initiative", - view = "show", - id = initiative.id - } +end +if initiator and initiator.accepted == false then + slot.put(" · ") + ui.link{ + text = _"Cancel refuse of invitation", + module = "initiative", + action = "remove_initiator", + params = { + initiative_id = initiative.id, + member_id = app.session.member.id + }, + routing = { + ok = { + mode = "redirect", + module = "initiative", + view = "show", + id = initiative.id } } - end - - -end ) + } +end util.help("initiative.show") @@ -308,3 +307,4 @@ end + diff -r 6c88b4bfb56c -r c587d8762e62 app/main/initiative/_show_voting.lua --- a/app/main/initiative/_show_voting.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/initiative/_show_voting.lua Sat Feb 25 11:51:37 2012 +0100 @@ -12,6 +12,8 @@ params = { initiative = initiative } } + slot.put("
") + ui.container{ attr = { class = "heading" }, content = _"Member voting" @@ -32,4 +34,37 @@ } } + slot.put("
") + + ui.container{ + attr = { class = "heading" }, + content = _"Voting details" + } + + ui.form{ + attr = { class = "vertical" }, + content = function() + + ui.field.boolean{ label = _"Direct majority", value = initiative.direct_majority } + ui.field.boolean{ label = _"Indirect majority", value = initiative.indirect_majority } + ui.field.text{ label = _"Schulze rank", value = tostring(initiative.schulze_rank) .. " (" .. _("Status quo: #{rank}", { rank = initiative.issue.status_quo_schulze_rank }) .. ")" } + local texts = {} + if initiative.reverse_beat_path then + texts[#texts+1] = _"reverse beat path to status quo (including ties)" + end + if initiative.multistage_majority then + texts[#texts+1] = _"possibly instable result caused by multistage majority" + end + if #texts == 0 then + texts[#texts+1] = _"none" + end + ui.field.text{ + label = _"Other failures", + value = table.concat(texts, ", ") + } + ui.field.boolean{ label = _"Eligible as winner", value = initiative.eligible } + end +} + + end diff -r 6c88b4bfb56c -r c587d8762e62 app/main/issue/_filters.lua --- a/app/main/issue/_filters.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/issue/_filters.lua Sat Feb 25 11:51:37 2012 +0100 @@ -12,6 +12,13 @@ selector_modifier = function(selector) end }, { + name = "open", + label = _"Open", + selector_modifier = function(selector) + selector:add_where("issue.closed ISNULL") + end + }, + { name = "new", label = _"New", selector_modifier = function(selector) @@ -94,89 +101,90 @@ end - -filters[#filters+1] = { - name = "filter_interest", - { - name = "any", - label = _"Any", - selector_modifier = function() end - }, - { - name = "my", - label = _"Interested", - selector_modifier = function() end - }, - { - name = "supported", - label = _"Supported", - selector_modifier = function() end - }, - { - name = "potentially_supported", - label = _"Potentially supported", - selector_modifier = function() end - }, - { - name = "initiated", - label = _"Initiated", - selector_modifier = function(selector) - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN initiator ON initiator.initiative_id = initiative.id AND initiator.member_id = ? AND initiator.accepted WHERE initiative.issue_id = issue.id)", member.id }) - end - }, -} - -local filter_interest = param.get_all_cgi()["filter_interest"] - -if filter_interest ~= "any" and filter_interest ~= nil and filter_interest ~= "initiated" then +if app.session.member then filters[#filters+1] = { - name = "filter_delegation", + name = "filter_interest", { name = "any", - label = _"Direct and by delegation", - selector_modifier = function(selector) - if filter_interest == "my" then - selector:left_join("delegating_interest_snapshot", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? AND filter_interest.event = issue.latest_snapshot_event", member.id }) - selector:left_join("interest", "filter_delegating_interest", { "filter_delegating_interest.issue_id = issue.id AND filter_delegating_interest.member_id = ? ", member.id }) - selector:add_where{ "filter_interest.member_id NOTNULL OR filter_delegating_interest.member_id NOTNULL" } - elseif filter_interest == "supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? LEFT JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id AND critical_opinion.member_id ISNULL LIMIT 1) OR EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id, member.id }) - elseif filter_interest == "potentially_supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id LIMIT 1) OR EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND NOT direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id, member.id, member.id }) - end - end + label = _"Any", + selector_modifier = function() end + }, + { + name = "my", + label = _"Interested", + selector_modifier = function() end + }, + { + name = "supported", + label = _"Supported", + selector_modifier = function() end + }, + { + name = "potentially_supported", + label = _"Potentially supported", + selector_modifier = function() end }, { - name = "direct", - label = _"Direct", + name = "initiated", + label = _"Initiated", selector_modifier = function(selector) - if filter_interest == "my" then - selector:join("interest", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? ", member.id }) - elseif filter_interest == "supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? LEFT JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id AND critical_opinion.member_id ISNULL LIMIT 1)", member.id, member.id }) - elseif filter_interest == "potentially_supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id LIMIT 1)", member.id, member.id }) - end + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN initiator ON initiator.initiative_id = initiative.id AND initiator.member_id = ? AND initiator.accepted WHERE initiative.issue_id = issue.id)", member.id }) end }, - { - name = "delegated", - label = _"By delegation", - selector_modifier = function(selector) - if filter_interest == "my" then - selector:join("delegating_interest_snapshot", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? AND filter_interest.event = issue.latest_snapshot_event", member.id }) - elseif filter_interest == "supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND direct_supporter_snapshot.satisfied LIMIT 1)", member.id }) - elseif filter_interest == "potentially_supported" then - selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND NOT direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id }) + } + + local filter_interest = param.get_all_cgi()["filter_interest"] + + if filter_interest ~= "any" and filter_interest ~= nil and filter_interest ~= "initiated" then + filters[#filters+1] = { + name = "filter_delegation", + { + name = "any", + label = _"Direct and by delegation", + selector_modifier = function(selector) + if filter_interest == "my" then + selector:left_join("delegating_interest_snapshot", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? AND filter_interest.event = issue.latest_snapshot_event", member.id }) + selector:left_join("interest", "filter_delegating_interest", { "filter_delegating_interest.issue_id = issue.id AND filter_delegating_interest.member_id = ? ", member.id }) + selector:add_where{ "filter_interest.member_id NOTNULL OR filter_delegating_interest.member_id NOTNULL" } + elseif filter_interest == "supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? LEFT JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id AND critical_opinion.member_id ISNULL LIMIT 1) OR EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id, member.id }) + elseif filter_interest == "potentially_supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id LIMIT 1) OR EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND NOT direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id, member.id, member.id }) + end end - end + }, + { + name = "direct", + label = _"Direct", + selector_modifier = function(selector) + if filter_interest == "my" then + selector:join("interest", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? ", member.id }) + elseif filter_interest == "supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? LEFT JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id AND critical_opinion.member_id ISNULL LIMIT 1)", member.id, member.id }) + elseif filter_interest == "potentially_supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = ? JOIN critical_opinion ON critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = ? WHERE initiative.issue_id = issue.id LIMIT 1)", member.id, member.id }) + end + end + }, + { + name = "delegated", + label = _"By delegation", + selector_modifier = function(selector) + if filter_interest == "my" then + selector:join("delegating_interest_snapshot", "filter_interest", { "filter_interest.issue_id = issue.id AND filter_interest.member_id = ? AND filter_interest.event = issue.latest_snapshot_event", member.id }) + elseif filter_interest == "supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND direct_supporter_snapshot.satisfied LIMIT 1)", member.id }) + elseif filter_interest == "potentially_supported" then + selector:add_where({ "EXISTS (SELECT 1 FROM initiative JOIN direct_supporter_snapshot ON direct_supporter_snapshot.initiative_id = initiative.id AND direct_supporter_snapshot.event = issue.latest_snapshot_event JOIN delegating_interest_snapshot ON delegating_interest_snapshot.delegate_member_ids[array_upper(delegating_interest_snapshot.delegate_member_ids, 1)] = direct_supporter_snapshot.member_id AND delegating_interest_snapshot.issue_id = issue.id AND delegating_interest_snapshot.member_id = ? AND delegating_interest_snapshot.event = issue.latest_snapshot_event WHERE initiative.issue_id = issue.id AND NOT direct_supporter_snapshot.satisfied LIMIT 1)", member.id, member.id }) + end + end + } } - } + end + end - -if member.id == app.session.member_id and param.get_all_cgi()["filter"] == "frozen" then +if app.session.member and member.id == app.session.member_id and (param.get_all_cgi()["filter"] == "frozen" or param.get_all_cgi()["filter"] == "finished") then filters[#filters+1] = { name = "filter_voting", { diff -r 6c88b4bfb56c -r c587d8762e62 app/main/issue/_list.lua --- a/app/main/issue/_list.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/issue/_list.lua Sat Feb 25 11:51:37 2012 +0100 @@ -100,6 +100,7 @@ end } ui.tag{ + attr = { class = "issue_policy_info" }, tag = "div", content = function() diff -r 6c88b4bfb56c -r c587d8762e62 app/main/issue/_show_head.lua --- a/app/main/issue/_show_head.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/issue/_show_head.lua Sat Feb 25 11:51:37 2012 +0100 @@ -114,6 +114,19 @@ end, } end + + if config.etherpad and app.session.member then + local url = config.etherpad.base_url .. "p/" .. config.etherpad.group_id .. "$Issue" .. issue.id + ui.link{ + attr = { target = "_blank" }, + external = url, + content = function() + ui.image{ static = "icons/16/comments.png" } + slot.put(_"Issue pad") + end, + } + end + end) if app.session.member_id and app.session.member:has_voting_right_for_unit_id(issue.area.unit_id) then diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_action/update.lua --- a/app/main/member/_action/update.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_action/update.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,4 +1,4 @@ -param.update(app.session.member, +local fields = { "organizational_unit", "internal_posts", "realname", @@ -13,12 +13,22 @@ "external_memberships", "external_posts", "statement" -) +} + +local update_args = { app.session.member } -if tostring(app.session.member.birthday) == "invalid_date" then - app.session.member.birthday = nil - slot.put_into("error", _"Date format is not valid. Please use following format: YYYY-MM-DD") - return false +for i, field in ipairs(fields) do + if not config.locked_profile_fields[field] then + param.update(app.session.member, field) + end +end + +if not config.locked_profile_fields.birthday then + if tostring(app.session.member.birthday) == "invalid_date" then + app.session.member.birthday = nil + slot.put_into("error", _"Date format is not valid. Please use following format: YYYY-MM-DD") + return false + end end app.session.member:save() diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_action/update_email.lua --- a/app/main/member/_action/update_email.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_action/update_email.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,5 +1,9 @@ local resend = param.get("resend", atom.boolean) +if not resend and config.locked_profile_fields.notify_email then + error("access denied") +end + if app.session.member.notify_email_locked then if resend then slot.put_into("error", _"We have sent an email with activation link already in the last hour. Please try again later.") diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_action/update_login.lua --- a/app/main/member/_action/update_login.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_action/update_login.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,3 +1,7 @@ +if config.locked_profile_fields.login then + error("access denied") +end + local login = param.get("login") login = util.trim(login) diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_action/update_name.lua --- a/app/main/member/_action/update_name.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_action/update_name.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,3 +1,7 @@ +if config.locked_profile_fields.name then + error("access denied") +end + local name = param.get("name") name = util.trim(name) diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_list.lua --- a/app/main/member/_list.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_list.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,4 +1,6 @@ local members_selector = param.get("members_selector", "table") +members_selector:add_where("member.activated NOTNULL") + local initiative = param.get("initiative", "table") local issue = param.get("issue", "table") local trustee = param.get("trustee", "table") diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/_profile.lua --- a/app/main/member/_profile.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/_profile.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,5 +1,7 @@ local member = param.get("member", "table") +local include_private_data = param.get("include_private_data", atom.boolean) + if not member then local member_id = param.get("member_id", atom.integer) if member_id then @@ -70,12 +72,18 @@ end } - - if member.ident_number then - ui.field.text{ label = _"Ident number", name = "ident_number" } + + if member.identification then + ui.field.text{ label = _"Identification", name = "identification" } end - ui.field.text{ label = _"Name", name = "name" } - + if member.name then + ui.field.text{ label = _"Screen name", name = "name" } + end + if include_private_data and member.login then + ui.field.text{ label = _"Login name", name = "login" } + ui.field.text{ label = _"Notification email", name = "notify_email" } + end + if member.realname and #member.realname > 0 then ui.field.text{ label = _"Real name", name = "realname" } end @@ -128,8 +136,16 @@ end if member.external_posts and #member.external_posts > 0 then ui.field.text{ label = _"Posts", name = "external_posts", multiline = true } + end + if member.admin then + ui.field.boolean{ label = _"Admin?", name = "admin" } end - slot.put('
') + if member.locked then + ui.field.boolean{ label = _"Locked?", name = "locked" } + end + if member.last_activity then + ui.field.text{ label = _"Last activity (updated daily)", value = format.date(member.last_activity) or _"not yet" } + end if member.statement and #member.statement > 0 then ui.container{ @@ -139,14 +155,5 @@ end } end - - if member.admin then - ui.field.boolean{ label = _"Admin?", name = "admin" } - end - if member.locked then - ui.field.boolean{ label = _"Locked?", name = "locked" } - end - ui.field.text{ label = _"Last activity (updated daily)", value = format.date(member.last_activity) or _"not yet" } - end } diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/edit.lua --- a/app/main/member/edit.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/edit.lua Sat Feb 25 11:51:37 2012 +0100 @@ -26,21 +26,22 @@ } }, content = function() - ui.field.text{ label = _"Organizational unit", name = "organizational_unit" } - ui.field.text{ label = _"Internal posts", name = "internal_posts" } - ui.field.text{ label = _"Real name", name = "realname" } - ui.field.text{ label = _"Birthday" .. " YYYY-MM-DD ", name = "birthday", attr = { id = "profile_birthday" } } + ui.field.text{ label = _"Identification", name = "identification", readonly = true } + ui.field.text{ label = _"Organizational unit", name = "organizational_unit", readonly = config.locked_profile_fields.organizational_unit } + ui.field.text{ label = _"Internal posts", name = "internal_posts", readonly = config.locked_profile_fields.internal_posts } + ui.field.text{ label = _"Real name", name = "realname", readonly = config.locked_profile_fields.realname } + ui.field.text{ label = _"Birthday" .. " YYYY-MM-DD ", name = "birthday", attr = { id = "profile_birthday" }, readonly = config.locked_profile_fields.birthday } ui.script{ static = "gregor.js/gregor.js" } util.gregor("profile_birthday", "document.getElementById('timeline_search_date').form.submit();") - ui.field.text{ label = _"Address", name = "address", multiline = true } - ui.field.text{ label = _"email", name = "email" } - ui.field.text{ label = _"xmpp", name = "xmpp_address" } - ui.field.text{ label = _"Website", name = "website" } - ui.field.text{ label = _"Phone", name = "phone" } - ui.field.text{ label = _"Mobile phone", name = "mobile_phone" } - ui.field.text{ label = _"Profession", name = "profession" } - ui.field.text{ label = _"External memberships", name = "external_memberships", multiline = true } - ui.field.text{ label = _"External posts", name = "external_posts", multiline = true } + ui.field.text{ label = _"Address", name = "address", multiline = true, readonly = config.locked_profile_fields.address } + ui.field.text{ label = _"email", name = "email", readonly = config.locked_profile_fields.email } + ui.field.text{ label = _"xmpp", name = "xmpp_address", readonly = config.locked_profile_fields.xmpp_address } + ui.field.text{ label = _"Website", name = "website", readonly = config.locked_profile_fields.website } + ui.field.text{ label = _"Phone", name = "phone", readonly = config.locked_profile_fields.phone } + ui.field.text{ label = _"Mobile phone", name = "mobile_phone", readonly = config.locked_profile_fields.mobile_phone } + ui.field.text{ label = _"Profession", name = "profession", readonly = config.locked_profile_fields.profession } + ui.field.text{ label = _"External memberships", name = "external_memberships", multiline = true, readonly = config.locked_profile_fields.external_memberships } + ui.field.text{ label = _"External posts", name = "external_posts", multiline = true, readonly = config.locked_profile_fields.external_posts } ui.field.select{ label = _"Wiki engine for statement", diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/settings.lua --- a/app/main/member/settings.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/settings.lua Sat Feb 25 11:51:37 2012 +0100 @@ -16,16 +16,23 @@ content = _"You can change the following settings:" } -local pages = { - { module = "member", view = "edit", text = _"Edit profile" }, - { module = "member", view = "edit_images", text = _"Upload images" }, - { view = "settings_display", text = _"Display settings" }, - { view = "settings_email", text = _"Change your notification email address" }, - { view = "settings_name", text = _"Change your name" }, - { view = "settings_login", text = _"Change your login" }, - { view = "settings_password", text = _"Change your password" }, - { view = "developer_settings", text = _"Developer settings" }, -} +local pages = {} + +pages[#pages+1] = { module = "member", view = "edit", text = _"Edit profile" } +pages[#pages+1] = { module = "member", view = "edit_images", text = _"Upload images" } +pages[#pages+1] = { view = "settings_notification", text = _"Notification settings" } +pages[#pages+1] = { view = "settings_display", text = _"Display settings" } +if not config.locked_profile_fields.notify_email then + pages[#pages+1] = { view = "settings_email", text = _"Change your notification email address" } +end +if not config.locked_profile_fields.name then + pages[#pages+1] = { view = "settings_name", text = _"Change your screen name" } +end +if not config.locked_profile_fields.login then + pages[#pages+1] = { view = "settings_login", text = _"Change your login" } +end +pages[#pages+1] = { view = "settings_password", text = _"Change your password" } +pages[#pages+1] = { view = "developer_settings", text = _"Developer settings" } ui.list{ attr = { class = "menu_list" }, diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/settings_notification.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/main/member/settings_notification.lua Sat Feb 25 11:51:37 2012 +0100 @@ -0,0 +1,185 @@ +function send_notification(event) + + local url + + local body = "" + + body = body .. _(" Unit: #{name}\n", { name = event.issue.area.unit.name }) + body = body .. _(" Area: #{name}\n", { name = event.issue.area.name }) + body = body .. _(" Issue: ##{id}\n", { id = event.issue_id }) + body = body .. _(" Policy: #{phase}\n", { phase = event.issue.policy.name }) + body = body .. _(" Phase: #{phase}\n\n", { phase = event.state }) + body = body .. _(" Event: #{event}\n\n", { event = event.event }) + + if event.initiative_id then + url = request.get_absolute_baseurl() .. "initiative/show/" .. event.initiative_id .. ".html" + elseif event.suggestion_id then + url = request.get_absolute_baseurl() .. "suggestion/show/" .. event.suggestion_id .. ".html" + else + url = request.get_absolute_baseurl() .. "issue/show/" .. event.issue_id .. ".html" + end + + body = body .. _(" URL: #{url}\n\n", { url = url }) + + if event.initiative_id then + local initiative = Initiative:by_id(event.initiative_id) + body = body .. _("i#{id}: #{name}\n\n", { id = initiative.id, name = initiative.name }) + else + local initiative_count = Initiative:new_selector() + :add_where{ "initiative.issue_id = ?", event.issue_id } + :count() + local initiatives = Initiative:new_selector() + :add_where{ "initiative.issue_id = ?", event.issue_id } + :add_order_by("initiative.supporter_count DESC") + :limit(3) + :exec() + for i, initiative in ipairs(initiatives) do + body = body .. _("i#{id}: #{name}\n", { id = initiative.id, name = initiative.name }) + end + if initiative_count - 3 > 0 then + body = body .. _("and #{count} more initiatives\n", { count = initiative_count }) + end + body = body .. "\n" + end + + if event.suggestion_id then + local suggestion = Suggestion:by_id(event.suggestion_id) + body = body .. _("#{name}\n\n", { name = suggestion.name }) + end + + slot.put("
", encode.html_newlines(body), "") + slot.put("
") +end + + + +slot.put_into("title", _"Notification settings") + +slot.select("actions", function() + ui.link{ + content = function() + ui.image{ static = "icons/16/cancel.png" } + slot.put(_"Cancel") + end, + module = "member", + view = "settings" + } +end) + + +util.help("member.settings.notification", _"Notification settings") + +ui.form{ + attr = { class = "vertical" }, + module = "member", + action = "update_notification", + routing = { + ok = { + mode = "redirect", + module = "index", + view = "index" + } + }, + content = function() + ui.tag{ tag = "p", _"Send me notifications about issues in following phases:" } + + ui.container{ content = function() + ui.tag{ + tag = "input", + attr = { type = "radio", name = "notification_level", value = "voting" } + } + ui.tag{ content = _"Voting phase" } + ui.tag{ tag = "ul", content = function() + ui.tag{ tag = "li", content = _"Voting of an issue in one of my areas or I'm interested in starts" } + end } + end } + + ui.container{ content = function() + ui.tag{ + tag = "input", + attr = { type = "radio", name = "notification_level", value = "frozen" } + } + ui.tag{ content = _"Frozen and voting phase" } + ui.tag{ tag = "ul", content = function() + ui.tag{ tag = "li", content = _"An issue in one of my areas or I'm interested in enters phase 'frozen'" } + ui.tag{ tag = "li", content = _"A new initiative is created in an issue I'm interested in" } + ui.tag{ tag = "li", content = _"Voting of an issue in one of my areas or I'm interested in starts" } + end } + end } + + ui.container{ content = function() + ui.tag{ + tag = "input", + attr = { type = "radio", name = "notification_level", value = "discussion" } + } + ui.tag{ content = _"Discussion, frozen and voting phase" } + ui.tag{ tag = "ul", content = function() + ui.tag{ tag = "li", content = _"An issue in one of my areas or I'm interested in enters phase 'discussion'" } + ui.tag{ tag = "li", content = _"A new initiative is created in an issue I'm interested in" } + ui.tag{ tag = "li", content = _"The draft of an initiative I'm supporting is updated" } + ui.tag{ tag = "li", content = _"An initiative I was supporting is revoked" } + ui.tag{ tag = "li", content = _"A new suggestion is created in an initiative I'm supporting" } + ui.tag{ tag = "li", content = _"An issue in one of my areas or I'm interested in enters phase 'frozen'" } + ui.tag{ tag = "li", content = _"Voting of an issue in one of my areas or I'm interested in starts" } + end } + end } + + ui.container{ content = function() + ui.tag{ + tag = "input", + attr = { type = "radio", name = "notification_level", value = "any" } + } + ui.tag{ content = _"Any phase" } + ui.tag{ tag = "ul", content = function() + ui.tag{ tag = "li", content = _"A new issue is created in one of my areas" } + ui.tag{ tag = "li", content = _"An issue in one of my areas or i'm interested in enters phase 'discussion'" } + ui.tag{ tag = "li", content = _"A new initiative is created in an issue I'm interested in" } + ui.tag{ tag = "li", content = _"The draft of an initiative I'm supporting is updated" } + ui.tag{ tag = "li", content = _"An initiative I was supporting is revoked" } + ui.tag{ tag = "li", content = _"A new suggestion is created in an initiative I'm supporting" } + ui.tag{ tag = "li", content = _"An issue in one of my areas or I'm interested in enters phase 'frozen'" } + ui.tag{ tag = "li", content = _"Voting of an issue in one of my areas or I'm interested in starts" } + end } + end } + + ui.container{ content = function() + ui.tag{ + tag = "input", + attr = { type = "radio", name = "notification_level", value = "none" } + } + ui.tag{ content = _"No notifications at all" } + end } + + + + ui.submit{ value = _"Change display settings" } + end +} + +local last_id = 6000; + +while last_id < 6050 do + + local event = Event:new_selector() + :add_where{ "event.id > ?", last_id } + :add_order_by("event.id") + :limit(1) + :optional_object_mode() + :exec() + + last_id = nil + if event then + last_id = event.id + local members_to_notify = Member:new_selector() + :join("event_seen_by_member", nil, { "event_seen_by_member.seen_by_member_id = member.id AND event_seen_by_member.notify_level <= member.notify_level AND event_seen_by_member.id = ?", event.id } ) + :add_where("member.activated NOTNULL AND member.notify_email NOTNULL") + :exec() + ui.container{ content = _("Event #{id} -> #{num} members", { id = event.id, num = #members_to_notify }) } + + send_notification(event) + + end +end + + +-- select event.id, event.occurrence, membership.member_id NOTNULL as membership, interest.member_id NOTNULL as interest, supporter.member_id NOTNULL as supporter, event.event, event.state, issue.id, initiative.name FROM event JOIN issue ON issue.id = event.issue_id LEFT JOIN membership ON membership.area_id = issue.area_id AND membership.member_id = 41 LEFT JOIN interest ON interest.issue_id = issue.id AND interest.member_id = 41 LEFT JOIN initiative ON initiative.id = event.initiative_id LEFT JOIN supporter ON supporter.initiative_id = initiative.id AND supporter.member_id = 41 WHERE (((event.event = 'issue_state_changed' OR event.event = 'initiative_created_in_new_issue') AND membership.member_id NOTNULL OR interest.member_id NOTNULL) OR (event.event = 'initiative_created_in_existing_issue' AND interest.member_id NOTNULL) OR ((event.event = 'initiative_revoked' OR event.event = 'new_draft_created' OR event.event = 'suggestion_created') AND supporter.member_id NOTNULL)) AND event.id > 7000 ORDER by event.id ASC LIMIT 1; \ No newline at end of file diff -r 6c88b4bfb56c -r c587d8762e62 app/main/member/show.lua --- a/app/main/member/show.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/member/show.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,5 +1,9 @@ local member = Member:by_id(param.get_id()) +if not member or not member.activated then + error("access denied") +end + app.html_title.title = member.name app.html_title.subtitle = _("Member") diff -r 6c88b4bfb56c -r c587d8762e62 app/main/policy/show.lua --- a/app/main/policy/show.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/policy/show.lua Sat Feb 25 11:51:37 2012 +0100 @@ -22,10 +22,36 @@ value = "≥ " .. tostring(policy.initiative_quorum_num) .. "/" .. tostring(policy.initiative_quorum_den) } ui.field.text{ - label = _"Majority", - value = (policy.majority_strict and ">" or "≥" ) .. " " .. tostring(policy.majority_num) .. "/" .. tostring(policy.majority_den) + label = _"Direct majority", + value = + (policy.direct_majority_strict and ">" or "≥" ) .. " " + .. tostring(policy.direct_majority_num) .. "/" + .. tostring(policy.direct_majority_den) + .. (policy.direct_majority_positive > 1 and ", " .. _("at least #{count} approvals", { count = policy.direct_majority_positive }) or "") + .. (policy.direct_majority_non_negative > 1 and ", " .. _("at least #{count} approvals or abstentions", { count = policy.direct_majority_non_negative }) or "") } + ui.field.text{ + label = _"Indirect majority", + value = + (policy.indirect_majority_strict and ">" or "≥" ) .. " " + .. tostring(policy.indirect_majority_num) .. "/" + .. tostring(policy.indirect_majority_den) + .. (policy.indirect_majority_positive > 1 and ", " .. _("at least #{count} approvals", { count = policy.indirect_majority_positive }) or "") + .. (policy.indirect_majority_non_negative > 1 and ", " .. _("at least #{count} approvals or abstentions", { count = policy.indirect_majority_non_negative }) or "") + } + + local texts = {} + if policy.no_reverse_beat_path then + texts[#texts+1] = _"no reverse beat path to status quo (including ties)" + end + if policy.no_multistage_majority then + texts[#texts+1] = _"prohibit potentially instable results caused by multistage majorities" + end + ui.field.text{ + label = _"Options", + value = table.concat(texts, ", ") + } ui.container{ attr = { class = "suggestion_content wiki" }, content = function() diff -r 6c88b4bfb56c -r c587d8762e62 app/main/unit/_list.lua --- a/app/main/unit/_list.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/unit/_list.lua Sat Feb 25 11:51:37 2012 +0100 @@ -5,6 +5,9 @@ columns = { { content = function(unit) + for i = 1, unit.depth - 1 do + slot.put(" ") + end ui.link{ text = unit.name, module = "area", view = "list", params = { unit_id = unit.id } } end } diff -r 6c88b4bfb56c -r c587d8762e62 app/main/vote/list.lua --- a/app/main/vote/list.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/app/main/vote/list.lua Sat Feb 25 11:51:37 2012 +0100 @@ -401,16 +401,32 @@ content = function() ui.tag{ content = "i" .. initiative.id .. ": " } ui.tag{ content = initiative.shortened_name } - if #initiators > 1 then - ui.container{ - attr = { style = "font-size: 80%;" }, - content = _"Initiators" .. ": " .. initiator_names_string + slot.put("
") + for i, initiator in ipairs(initiators) do + ui.link{ + attr = { class = "clickable" }, + content = function () + execute.view{ + module = "member_image", + view = "_show", + params = { + member = initiator, + image_type = "avatar", + show_dummy = true, + class = "micro_avatar", + popup_text = text + } + } + end, + module = "member", view = "show", id = initiator.id } - else - ui.container{ - attr = { style = "font-size: 80%;" }, - content = _"Initiator" .. ": " .. initiator_names_string + slot.put(" ") + ui.link{ + attr = { class = "clickable" }, + text = initiator.name, + module = "member", view = "show", id = initiator.id } + slot.put(" ") end end } diff -r 6c88b4bfb56c -r c587d8762e62 config/default.lua --- a/config/default.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/config/default.lua Sat Feb 25 11:51:37 2012 +0100 @@ -20,6 +20,10 @@ } } +config.locked_profile_fields = { + field_name = true, + notify_email = true +} config.member_image_content_type = "image/jpeg" config.member_image_convert_func = { diff -r 6c88b4bfb56c -r c587d8762e62 config/development.lua --- a/config/development.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/config/development.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,4 +1,4 @@ -config.absolute_base_url = "http://10.8.33.34/lf/" +config.absolute_base_url = "http://10.1.11.5/lf/" execute.config("default") @@ -42,3 +42,11 @@ -- "custom_script", -- "document.getElementById('trace_show').onclick();" --) + +config.etherpad = { + base_url = "http://10.1.11.5:9001/", + api_base = "http://127.0.0.1:9001/", + api_key = "g5XAVrRb5EgPuEqIdVrRNt2Juipx3PoH", + group_id = "g.7WDKN3StkEyuWkyN", + cookie_path = "/" +} diff -r 6c88b4bfb56c -r c587d8762e62 env/net/curl.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/net/curl.lua Sat Feb 25 11:51:37 2012 +0100 @@ -0,0 +1,10 @@ +function net.curl(url) + local stdout, errmsg, status = os.pfilter(nil, "curl", url) + if not stdout then + error("Error while executing curl: " .. errmsg) + end + if status ~= 0 then + return nil + end + return stdout +end \ No newline at end of file diff -r 6c88b4bfb56c -r c587d8762e62 env/ui/tabs.lua --- a/env/ui/tabs.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/env/ui/tabs.lua Sat Feb 25 11:51:37 2012 +0100 @@ -1,6 +1,8 @@ function ui.tabs(tabs) + local attr = tabs.attr or {} + attr.class = (attr.class and attr.class .. " " or "") .. "ui_tabs" ui.container{ - attr = { class = "ui_tabs" }, + attr = attr, content = function() local params = param.get_all_cgi() local current_tab = params["tab"] diff -r 6c88b4bfb56c -r c587d8762e62 model/event.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/event.lua Sat Feb 25 11:51:37 2012 +0100 @@ -0,0 +1,10 @@ +Event = mondelefant.new_class() +Event.table = 'event' + +Event:add_reference{ + mode = 'm1', + to = "Issue", + this_key = 'issue_id', + that_key = 'id', + ref = 'issue', +} \ No newline at end of file diff -r 6c88b4bfb56c -r c587d8762e62 model/event_seen_by_member.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/model/event_seen_by_member.lua Sat Feb 25 11:51:37 2012 +0100 @@ -0,0 +1,4 @@ +EventSeenByMember = mondelefant.new_class() +EventSeenByMember.table = 'event_seen_by_member' + + diff -r 6c88b4bfb56c -r c587d8762e62 model/member.lua --- a/model/member.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/model/member.lua Sat Feb 25 11:51:37 2012 +0100 @@ -325,6 +325,30 @@ :add_where("active") end +function Member.object:send_invitation() + trace.disable() + self.invite_code = multirand.string( 24, "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ) + local content = slot.use_temporary(function() + slot.put(_"Hello\n\n") + slot.put(_"You are invited to LiquidFeedback. To register please click the following link:\n\n") + slot.put(config.absolute_base_url .. "index/register.html?invite_key=" .. self.invite_code .. "\n\n") + slot.put(_"If this link is not working, please open following url in your web browser:\n\n") + slot.put(config.absolute_base_url .. "index/register.html\n\n") + slot.put(_"On that page please enter the invite key:\n\n") + slot.put(self.invite_code .. "\n\n") + end) + local success = net.send_mail{ + envelope_from = config.mail_envelope_from, + from = config.mail_from, + reply_to = config.mail_reply_to, + to = self.notify_email_unconfirmed or self.notify_email, + subject = config.mail_subject_prefix .. _"Invitation to LiquidFeedback", + content_type = "text/plain; charset=UTF-8", + content = content + } + return success +end + function Member.object:set_notify_email(notify_email) trace.disable() local expiry = db:query("SELECT now() + '7 days'::interval as expiry", "object").expiry diff -r 6c88b4bfb56c -r c587d8762e62 model/unit.lua --- a/model/unit.lua Fri Feb 17 15:16:02 2012 +0100 +++ b/model/unit.lua Sat Feb 25 11:51:37 2012 +0100 @@ -21,8 +21,39 @@ ref = 'members' } -function Unit:get_flattened_tree() - -- TODO implement +function recursive_add_child_units(units, parent_unit) + parent_unit.childs = {} + for i, unit in ipairs(units) do + if unit.parent_id == parent_unit.id then + parent_unit.childs[#(parent_unit.childs)+1] = unit + recursive_add_child_units(units, unit) + end + end +end + +function recursive_get_child_units(units, parent_unit, depth) + for i, unit in ipairs(parent_unit.childs) do + unit.depth = depth + units[#units+1] = unit + recursive_get_child_units(units, unit, depth + 1) + end +end - return Unit:new_selector():exec() +function Unit:get_flattened_tree() + local units = Unit:new_selector():add_order_by("name"):exec() + local unit_tree = {} + for i, unit in ipairs(units) do + if not unit.parent_id then + unit_tree[#unit_tree+1] = unit + recursive_add_child_units(units, unit) + end + end + local depth = 1 + local units = {} + for i, unit in ipairs(unit_tree) do + unit.depth = depth + units[#units+1] = unit + recursive_get_child_units(units, unit, depth + 1) + end + return units end diff -r 6c88b4bfb56c -r c587d8762e62 static/style.css --- a/static/style.css Fri Feb 17 15:16:02 2012 +0100 +++ b/static/style.css Sat Feb 25 11:51:37 2012 +0100 @@ -269,9 +269,7 @@ .slot_initiative_head { background: -webkit-gradient(linear, left top, left bottom, - /*color-stop(0%,#AFEFB9), color-stop(100%,#ffffff) */ - color-stop(0%, #fff), color-stop(15%,#e7e7e7), color-stop(100%,#fff) - ); + color-stop(0%,#e7e7e7), color-stop(66%,#fff)); margin-top: 2ex; padding-left: 1em; padding-top: 2ex; @@ -328,7 +326,9 @@ } - +.member_image_photo { + border-radius: 8px; +} /************************************************************************* * vote info / delegation @@ -469,7 +469,6 @@ margin-right: 1em; } - /************************************************************************* * ui.tab */ @@ -823,6 +822,10 @@ font-size: 125%; } +.issues .issue .issue_policy_info { + font-style: italic; +} + .issues .issue .interest_by_delegation { float: right; } @@ -851,7 +854,7 @@ .initiative_link.supported, .initiative_link.potentially_supported { - background-color: #C9FFD1; + background-color: #cdf; border-radius: 5px; background: -webkit-radial-gradient(center, ellipse cover, #cdf 50%,#fff 100%); /* Chrome10+,Safari5.1+ */ } @@ -975,6 +978,9 @@ border-radius: 8px; } +.member_statement { + margin-right: 250px; +} #suggestion_description { height: 15ex; @@ -1021,6 +1027,7 @@ background-color: #dfd; padding: 1ex; margin-bottom: 2ex; + border-radius: 8px; } .not_admitted_info, @@ -1153,15 +1160,21 @@ * Voting */ +#voting_form { + margin-top: 20px; +} + #voting { position: relative; } + #voting .approval, .abstention, .disapproval { border: 2px black solid; - margin-top: 5ex; + margin-top: 2ex; margin-bottom: 5ex; padding: 1ex; padding-bottom: 2ex; + border-radius: 8px; } #voting .approval { background-color: #9f9; @@ -1187,8 +1200,9 @@ #voting .movable { position: relative; border: 1px black solid; - margin: 1ex; + margin-top: 1ex; padding: 0.5ex; + border-radius: 8px; } #voting .voting_form_active .movable { cursor: pointer;