summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzul <azul@leap.se>2014-07-04 15:40:54 +0200
committerAzul <azul@leap.se>2014-07-05 10:21:07 +0200
commit87e9ccbcdf4f99dd898b0715750092a27fff7e94 (patch)
tree9e49a287c6e95d92323253d899afa367a6f1e14e
parent24d108e15c38ca572d5339a39cb110d9067c0b3d (diff)
Enable unblocking handles in identities tab
There's an identities tab now for admins that will allow unblocking blocked handles. It should be easy to expand for aliases and forwards and other types of actions such as editing.
-rw-r--r--app/assets/stylesheets/leap.scss21
-rw-r--r--app/controllers/identities_controller.rb28
-rw-r--r--app/helpers/link_helper.rb25
-rw-r--r--app/helpers/table_helper.rb13
-rw-r--r--app/models/identity.rb20
-rw-r--r--app/views/common/_action.html.haml2
-rw-r--r--app/views/common/_navigation_item.html.haml3
-rw-r--r--app/views/common/_table.html.haml18
-rw-r--r--app/views/identities/_identity.html.haml7
-rw-r--r--app/views/identities/index.html.haml4
-rw-r--r--app/views/layouts/_admin_navigation_item.html.haml3
-rw-r--r--app/views/layouts/_header.html.haml6
-rw-r--r--config/locales/users.en.yml7
-rw-r--r--config/routes.rb2
-rw-r--r--engines/support/app/views/tickets/index.html.haml16
-rw-r--r--test/factories.rb6
-rw-r--r--test/functional/identities_controller_test.rb42
-rw-r--r--test/integration/browser/admin_test.rb24
-rw-r--r--test/support/browser_integration_test.rb2
19 files changed, 227 insertions, 22 deletions
diff --git a/app/assets/stylesheets/leap.scss b/app/assets/stylesheets/leap.scss
index 77104e5..3b7075c 100644
--- a/app/assets/stylesheets/leap.scss
+++ b/app/assets/stylesheets/leap.scss
@@ -145,6 +145,27 @@ input, textarea {
}
//
+// IDENTITIES
+//
+
+// Color code for the identity labels
+.identity{
+ &.main_email .label {
+ @extend .label-info
+ }
+ &.alias .label {
+ @extend .label-success
+ }
+ &.forward .label {
+ @extend .label-warning
+ }
+ &.disabled .label {
+ @extend .label-default
+ }
+}
+
+
+//
// BORING DEFAULT MASTHEAD
//
diff --git a/app/controllers/identities_controller.rb b/app/controllers/identities_controller.rb
new file mode 100644
index 0000000..624e38a
--- /dev/null
+++ b/app/controllers/identities_controller.rb
@@ -0,0 +1,28 @@
+class IdentitiesController < ApplicationController
+
+ before_filter :require_login
+ before_filter :require_admin
+ before_filter :fetch_identity, only: :destroy
+ before_filter :protect_main_email, only: :destroy
+
+ def index
+ @identities = Identity.all
+ end
+
+ def destroy
+ @identity.destroy
+ redirect_to identities_path
+ end
+
+ protected
+ def fetch_identity
+ @identity = Identity.find(params[:id])
+ end
+
+ def protect_main_email
+ if @identity.status == :main_email
+ flash[:error] = "You cannot destroy the main email. Remove or Rename the user instead."
+ redirect_to identities_path
+ end
+ end
+end
diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb
index 55e392b..ddb063e 100644
--- a/app/helpers/link_helper.rb
+++ b/app/helpers/link_helper.rb
@@ -1,5 +1,30 @@
module LinkHelper
+ Action = Struct.new(:target, :verb, :options) do
+ def to_partial_path; 'common/action'; end
+ def label; options[:label]; end
+ def class; verb; end
+ def url
+ case verb
+ when :show, :destroy then target
+ when :edit, :new then [verb, target]
+ end
+ end
+
+ def html_options
+ if verb == :destroy
+ {method: :delete}
+ end
+ end
+ end
+
+ def actions(target)
+ target.actions.map do |action|
+ Action.new target, action,
+ label: t(".#{action}", cascade: true)
+ end
+ end
+
#
# markup for bootstrap button
#
diff --git a/app/helpers/table_helper.rb b/app/helpers/table_helper.rb
new file mode 100644
index 0000000..16a7019
--- /dev/null
+++ b/app/helpers/table_helper.rb
@@ -0,0 +1,13 @@
+module TableHelper
+
+ # we do the translation here so the .key lookup is relative
+ # to the partial the helper was called from.
+ def table(content, columns)
+ render 'common/table',
+ content: content,
+ columns: columns,
+ headers: columns.map {|h| t(".#{h}", cascading: true) },
+ none: t('.none', cascading: true)
+ end
+
+end
diff --git a/app/models/identity.rb b/app/models/identity.rb
index e7b5785..e09d7f2 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -95,6 +95,18 @@ class Identity < CouchRest::Model::Base
}
end
+ def status
+ return :blocked if disabled?
+ case destination
+ when address
+ :main_email
+ when /@#{APP_CONFIG[:domain]}\Z/i,
+ :alias
+ else
+ :forward
+ end
+ end
+
def enabled?
self.user_id
end
@@ -103,6 +115,14 @@ class Identity < CouchRest::Model::Base
!enabled?
end
+ def actions
+ if enabled?
+ [] # [:show, :edit]
+ else
+ [:destroy]
+ end
+ end
+
def disable
self.destination = nil
self.user_id = nil
diff --git a/app/views/common/_action.html.haml b/app/views/common/_action.html.haml
new file mode 100644
index 0000000..71ffd96
--- /dev/null
+++ b/app/views/common/_action.html.haml
@@ -0,0 +1,2 @@
+%li.action{class: action.class}
+ =link_to action.label, action.url, action.html_options
diff --git a/app/views/common/_navigation_item.html.haml b/app/views/common/_navigation_item.html.haml
new file mode 100644
index 0000000..02c54c8
--- /dev/null
+++ b/app/views/common/_navigation_item.html.haml
@@ -0,0 +1,3 @@
+- item = navigation_item.to_s
+%li{:class => ("active" if controller?(item))}
+ = link_to t(".#{item}", cascade: true), polymorphic_url(item)
diff --git a/app/views/common/_table.html.haml b/app/views/common/_table.html.haml
new file mode 100644
index 0000000..3c6bf2e
--- /dev/null
+++ b/app/views/common/_table.html.haml
@@ -0,0 +1,18 @@
+-#
+-# A simple table with headers, content and a message if there is no
+-# content.
+-# You can use the table helper method to translate the headers and
+-# error message.
+-#
+%table.table.table-striped.table-bordered
+ %thead
+ %tr
+ - headers.each do |header|
+ %th= header
+ %tbody
+ - if content.any?
+ = render content.all
+ - else
+ %tr
+ %td{:colspan=>headers.count}= none
+
diff --git a/app/views/identities/_identity.html.haml b/app/views/identities/_identity.html.haml
new file mode 100644
index 0000000..7c4aeda
--- /dev/null
+++ b/app/views/identities/_identity.html.haml
@@ -0,0 +1,7 @@
+%tr[identity]{class: identity.status}
+ %td
+ %span.label= t(".#{identity.status}", cascading: true)
+ %td= identity.login
+ %td= identity.destination
+ %td
+ %ul.list-inline= render actions(identity)
diff --git a/app/views/identities/index.html.haml b/app/views/identities/index.html.haml
new file mode 100644
index 0000000..cabcccd
--- /dev/null
+++ b/app/views/identities/index.html.haml
@@ -0,0 +1,4 @@
+-@show_navigation = false
+
+= table @identities, %w(type username destination actions)
+-# = paginate @identities
diff --git a/app/views/layouts/_admin_navigation_item.html.haml b/app/views/layouts/_admin_navigation_item.html.haml
new file mode 100644
index 0000000..8dd8a39
--- /dev/null
+++ b/app/views/layouts/_admin_navigation_item.html.haml
@@ -0,0 +1,3 @@
+- item = admin_navigation_item.to_s
+%li{:class => ("active" if controller?(item))}
+ = link_to t(".#{item}", cascade: true), path_for(item)
diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml
index e827f60..ff14af9 100644
--- a/app/views/layouts/_header.html.haml
+++ b/app/views/layouts/_header.html.haml
@@ -1,10 +1,6 @@
- if admin?
%ul.nav.nav-tabs
- = # this navigation isn't quite right. also, we will want to active for an identity controller once it is added.
- %li{:class => ("active" if controller?('users', 'overviews') || params[:user_id])}
- = link_to t(".users"), users_path
- %li{:class => ("active" if controller?('tickets') && !params[:user_id])}
- = link_to t(".tickets", cascade: true), tickets_path
+ = render partial: 'common/navigation_item', collection: [:users, :identities, :tickets]
%li
= link_to t(:logout), logout_path, :method => :delete
- if @user && @show_navigation
diff --git a/config/locales/users.en.yml b/config/locales/users.en.yml
index f0fcb3d..bebf1cf 100644
--- a/config/locales/users.en.yml
+++ b/config/locales/users.en.yml
@@ -1,6 +1,9 @@
en:
- layouts:
- users: "Users"
+ common:
+ navigation_item:
+ users: "Users"
+ identities: "Usernames"
+ tickets: "Tickets"
user_control_panel: "user control panel"
account_settings: "Account Settings"
username: "Username"
diff --git a/config/routes.rb b/config/routes.rb
index 4ccfe62..468e14e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -48,6 +48,8 @@ LeapWeb::Application.routes.draw do
post 'deactivate', on: :member
post 'enable', on: :member
end
+
+ resources :identities, :only => [:index, :destroy]
end
get "/.well-known/host-meta" => 'webfinger#host_meta'
diff --git a/engines/support/app/views/tickets/index.html.haml b/engines/support/app/views/tickets/index.html.haml
index 526cd6d..d107ce2 100644
--- a/engines/support/app/views/tickets/index.html.haml
+++ b/engines/support/app/views/tickets/index.html.haml
@@ -1,19 +1,5 @@
- @show_navigation = params[:user_id].present?
= render 'tickets/tabs'
-
-%table.table.table-striped.table-bordered
- %thead
- %tr
- %th= t(".subject")
- %th= t(".created")
- %th= t(".updated")
- %th= t(".voices")
- %tbody
- - if @tickets.any?
- = render @tickets.all
- - else
- %tr
- %td{:colspan=>4}= t(".none")
-
+= table @tickets, %w(subject created updated voices)
= paginate @tickets
diff --git a/test/factories.rb b/test/factories.rb
index bebda5c..a96d48c 100644
--- a/test/factories.rb
+++ b/test/factories.rb
@@ -29,6 +29,12 @@ FactoryGirl.define do
end
+ # Identities can have a lot of different purposes - alias, forward, ...
+ # So far this is a blocked handle only.
+ factory :identity do
+ address {Faker::Internet.user_name + '@' + APP_CONFIG[:domain]}
+ end
+
factory :token do
user
end
diff --git a/test/functional/identities_controller_test.rb b/test/functional/identities_controller_test.rb
new file mode 100644
index 0000000..fcdeaa2
--- /dev/null
+++ b/test/functional/identities_controller_test.rb
@@ -0,0 +1,42 @@
+require 'test_helper'
+
+class IdentitiesControllerTest < ActionController::TestCase
+
+ test "admin can list active and blocked ids" do
+ login :is_admin? => true
+ get :index
+ assert_response :success
+ assert ids = assigns(:identities)
+ end
+
+ test "non-admin can't list usernames" do
+ login
+ get :index
+ assert_access_denied
+ end
+
+ test "requires login" do
+ get :index
+ assert_login_required
+ end
+
+ test "admin can unblock username" do
+ # an identity without user_id and destination is a blocked handle
+ identity = FactoryGirl.create :identity
+ login :is_admin? => true
+ delete :destroy, id: identity.id
+ assert_response :redirect
+ assert_nil Identity.find(identity.id)
+ end
+
+ test "admin cannot remove main identity" do
+ user = FactoryGirl.create :user
+ identity = FactoryGirl.create :identity,
+ Identity.attributes_from_user(user)
+ login :is_admin? => true
+ delete :destroy, id: identity.id
+ assert_response :redirect
+ assert_equal identity, Identity.find(identity.id)
+ end
+
+end
diff --git a/test/integration/browser/admin_test.rb b/test/integration/browser/admin_test.rb
new file mode 100644
index 0000000..2d3f988
--- /dev/null
+++ b/test/integration/browser/admin_test.rb
@@ -0,0 +1,24 @@
+require 'test_helper'
+
+class AdminTest < BrowserIntegrationTest
+
+ test "clear blocked handle" do
+ id = FactoryGirl.create :identity
+ submit_signup(id.login)
+ assert page.has_content?('has already been taken')
+ login
+ with_config admins: [@user.login] do
+ visit '/'
+ click_on "Usernames"
+ within "##{dom_id(id)}" do
+ assert page.has_content? id.login
+ click_on "Destroy"
+ end
+ assert page.has_no_content? id.login
+ click_on 'Log Out'
+ end
+ submit_signup(id.login)
+ assert page.has_content?("Welcome #{id.login}")
+ click_on 'Log Out'
+ end
+end
diff --git a/test/support/browser_integration_test.rb b/test/support/browser_integration_test.rb
index 4fec59f..c01b8a1 100644
--- a/test/support/browser_integration_test.rb
+++ b/test/support/browser_integration_test.rb
@@ -5,6 +5,8 @@
#
class BrowserIntegrationTest < ActionDispatch::IntegrationTest
+ # let's use dom_id inorder to identify sections
+ include ActionController::RecordIdentifier
CONFIG_RU = (Rails.root + 'config.ru').to_s
OUTER_APP = Rack::Builder.parse_file(CONFIG_RU).first