Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Thu, Apr 24, 4:12 PM
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 01aae98..365ef77 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,48 +1,55 @@
class UsersController < ApplicationController
before_action :authenticate_user!
- before_action :user, only: [:mute, :unmute, :token, :generate_token]
+ before_action :user, only: [:mute, :unmute, :mute_all, :token, :generate_token]
# GET /users/1/token
def token
end
# POST /users/1/generate_token
def generate_token
@user.token = SecureRandom.hex(10)
@user.save!
redirect_to token_user_path(@user)
end
# PUT /users/1/unsubscribe/2
def mute
domain = show_domain_scope.find(params[:domain_id])
@user.subscriptions.find_or_create_by!(domain: domain)
redirect_to domains_url, notice: "Successfully unsubscribed from #{domain.name} notifications!"
end
# PUT /users/1/subscribe/2
def unmute
domain = show_domain_scope.find(params[:domain_id])
# Drop all opt-outs
@user.subscriptions.where(domain: domain).delete_all
redirect_to domains_url, notice: "Successfully subscribed to #{domain.name} notifications!"
end
+ # PUT /users/1/domains/mute
+ def mute_all
+ @user.mute_all_domains
+
+ redirect_to domains_url, notice: "Successfully unsubscribed from all domain notifications!"
+ end
+
private
def user
@user ||= User.find(params[:user_id] || params[:id])
# Guard access to other user tokens
if current_user.id != @user.id && !admin?
redirect_to(root_path, alert: 'You need admin rights for that!')
end
@user
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 51e2f75..66f7508 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,32 +1,48 @@
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :memberships
has_many :groups, through: :memberships
has_many :subscriptions, dependent: :delete_all
scope :orphans, -> { includes(:memberships).where(:memberships => { user_id: nil }) }
# Check if the user can change his password
#
# Remote users are not able to change their password
def can_change_password?
!identifier?
end
def to_api
Hash[
:id, id,
:email, email
].with_indifferent_access
end
def self.find_for_database_authentication(conditions)
# Override devise method for database auth
# We only want to auth local user via the database.
find_first_by_auth_conditions(conditions, identifier: '')
end
+
+ def mute_all_domains
+ ActiveRecord::Base.transaction do
+ domain_ids = Domain.where(group: groups).pluck(:id)
+ domain_ids.each { |did|
+
+ sub = self.subscriptions.create(domain_id: did)
+ if !sub.valid?
+ # Allow only domain_id (uniqueness) errors
+ raise x.errors.full_messages.join(', ') if sub.errors.size > 1
+ raise x.errors.full_messages.join(', ') if !sub.errors[:domain_id]
+ end
+
+ }
+ end
+ end
end
diff --git a/app/views/shared/_nav.html.erb b/app/views/shared/_nav.html.erb
index e05d35d..a6281ba 100644
--- a/app/views/shared/_nav.html.erb
+++ b/app/views/shared/_nav.html.erb
@@ -1,57 +1,59 @@
<!-- Fixed navbar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">WebDNS</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/domains">Domains</a></li>
<form class="navbar-form navbar-left" role="search" action="/records/search" method="get">
<div class="form-group">
<input type="text" name="q" id="q" class="form-control" placeholder="Records" value="<%= params[:q] %>">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
</ul>
<ul class="nav navbar-nav navbar-right">
<% if admin? %>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Admin<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="/admin/groups/">Groups</a></li>
<li><a href="/admin/jobs/">Jobs</a></li>
<li><a href="/admin/users/orphans/">Orphans</a></li>
</ul>
</li>
<% end %>
<% if user_signed_in? %>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<%= current_user.try(:email) %>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<% if current_user.can_change_password? %>
<li><%= link_to('Change Password', edit_user_registration_path) %></li>
<% end %>
+ <li><%= link_to('Mute notifications', mute_user_domains_path(current_user), method: :put,
+ title: 'Mute all domain notifications') %></li>
<li><%= link_to('API Token', token_user_path(current_user)) %></li>
<li><%= link_to('Logout', destroy_user_session_path, method: :delete) %></li>
</ul>
</li>
<% end %>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
diff --git a/config/routes.rb b/config/routes.rb
index 6c277dc..3dac3f1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,86 +1,87 @@
Rails.application.routes.draw do
# Override devise user removal
devise_scope :users do
delete :users, to: redirect('/')
end
devise_for :users
get '/auth/saml', to: 'auth#saml'
root to: redirect('/domains')
resources :users, only: [] do
get :token, to: 'users#token', on: :member
post :generate_token, to: 'users#generate_token', on: :member
resources :domains, only: [] do
put :mute, to: 'users#mute'
put :unmute, to: 'users#unmute'
+ put :mute, to: 'users#mute_all', on: :collection
end
end
resources :groups, only: [:show] do
get :search_member,
to: 'groups#search_member', on: :member
post :members,
to: 'groups#create_member', as: :create_member, on: :member
delete 'member/:user_id',
to: 'groups#destroy_member', as: :destroy_member, on: :member
end
resources :domains do
get :edit_dnssec, to: 'domains#edit_dnssec', on: :member
delete :full_destroy, to: 'domains#full_destroy', on: :member
resources :records, except: [:index, :show] do
# Reuse records#update instead of introducing new controller actions
#
# rubocop:disable Style/AlignHash
put :disable, to: 'records#update', on: :member,
defaults: { record: { disabled: true } }
put :enable, to: 'records#update', on: :member,
defaults: { record: { disabled: false } }
put :editable, to: 'records#editable', on: :collection
post :valid, to: 'records#valid', on: :collection
post :bulk, to: 'records#bulk', on: :collection
# rubocop:enable Style/AlignHash
end
end
get '/records/search', to: 'records#search'
# Admin
namespace :admin do
root to: redirect('/admin/groups')
resources :groups, except: [:show]
resources :jobs, only: [:index, :destroy] do
put :done, to: 'jobs#update', on: :member,
defaults: { job: { status: 1 } }
put :pending, to: 'jobs#update', on: :member,
defaults: { job: { status: 0 } }
get '/type/:category', to: 'jobs#index', on: :collection,
constraints: proc { |req| ['completed', 'pending'].include?(req.params[:category]) }
end
resources :users, only: [:destroy] do
get :orphans, to: 'users#orphans', on: :collection
put :update_groups, to: 'users#update_groups', on: :collection
end
end
# API
scope '/api' do
get :ping, to: 'api#ping'
get :whoami, to: 'api#whoami'
get '/domain/:domain/list', to: 'api#list', constraints: { domain: /[^\/]+/}
post '/domain/:domain/bulk', to: 'api#bulk', constraints: { domain: /[^\/]+/}
get :domains, to: 'api#domains'
end if WebDNS.settings[:api]
# Private
put 'private/replace_ds', to: 'private#replace_ds'
put 'private/trigger_event', to: 'private#trigger_event'
get 'private/zones', to: 'private#zones'
get 'help/api', to: 'help#api'
end
diff --git a/test/models/subscription_test.rb b/test/models/subscription_test.rb
index b3f9a84..74018eb 100644
--- a/test/models/subscription_test.rb
+++ b/test/models/subscription_test.rb
@@ -1,17 +1,35 @@
require 'test_helper'
class SubscriptionTest < ActiveSupport::TestCase
test 'single subscription for a domain' do
domain = create(:domain_with_subscriptions)
assert_equal 1, domain.opt_outs.count
subscription = domain.opt_outs.first
assert_equal true, subscription.disabled
user = subscription.user
user.reload
assert_equal domain, user.subscriptions.first.domain
end
+
+ test 'mute all domains for a user' do
+ d1 = create(:domain_with_subscriptions)
+ d2 = create(:domain_with_subscriptions)
+ user = create(:user)
+
+ # Add user to the groups
+ d1.group.users << user
+ d2.group.users << user
+
+ # Opt out from notifications
+ user.mute_all_domains
+ # Ensure this is re-entrant
+ user.mute_all_domains
+
+ # Assert 2 opt-out domains
+ assert_equal 2, user.subscriptions.count
+ end
end

Event Timeline