Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Wed, Jan 21, 1:56 AM
diff --git a/.rubocop.yml b/.rubocop.yml
index e224bf5..0b70a44 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,32 +1,32 @@
AllCops:
DisplayCopNames: true
Exclude:
- 'lib/capistrano/**/*'
- 'vendor/**/*'
- 'unicorn.conf.rb'
Metrics/LineLength:
Max: 120
Metrics/AbcSize:
- Max: 16
+ Max: 18
Documentation:
Enabled: false
Style/NegatedIf:
Enabled: false
Style/Not:
Enabled: false
Style/WordArray:
Enabled: false
Style/TrailingComma:
Enabled: false
Style/BlockDelimiters:
Enabled: false
Style/TrailingBlankLines:
Enabled: false
Style/EmptyLinesAroundClassBody:
Enabled: false
Style/EmptyLinesAroundModuleBody:
Enabled: false
Lint/HandleExceptions:
Enabled: false
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 5a70282..3b17d27 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -1,30 +1,48 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery.min
//= require jquery_ujs
//= require bootstrap.min
//= require typeahead.bundle.min
//= require_tree .
$(function() {
// Show priority on MX record only
$('#record_type').change(function() {
if ($(this).val() == 'MX') {
$('#record_prio').parents('div.form-group').removeClass('hidden');
} else {
$('#record_prio').parents('div.form-group').addClass('hidden');
}
});
+ var searchMembersGroup = $('#js-search-member').data('group');
+ var searchMembers = new Bloodhound({
+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
+ remote: {
+ url: '/groups/' + searchMembersGroup + '/search_member.json?q=%QUERY',
+ wildcard: '%QUERY'
+ }
+ });
+
+ $('#js-search-member').typeahead({
+ hint: true,
+ minLength: 2
+ }, {
+ name: 'members',
+ display: 'email',
+ source: searchMembers
+ });
});
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
new file mode 100644
index 0000000..1099405
--- /dev/null
+++ b/app/controllers/groups_controller.rb
@@ -0,0 +1,47 @@
+class GroupsController < ApplicationController
+ before_action :authenticate_user!
+
+ before_action :group, only: [:show, :create_member, :destroy_member, :search_member]
+ before_action :user, only: [:destroy_member]
+
+ # GET /groups/1
+ def show
+ end
+
+ # POST /groups/1/members/
+ def create_member
+ @user = User.find_by_email!(params[:email])
+ membership = @group.memberships.find_or_create_by!(user_id: @user.id)
+
+ redirect_to @group, notice: "#{membership.user.email} is now a member of #{@group.name}"
+ end
+
+ # DELETE /groups/1/member/1
+ def destroy_member
+ membership = @group.memberships.find_by!(user_id: user.id)
+ membership.destroy!
+
+ redirect_to @group, notice: "#{membership.user.email} was successfully removed from #{@group.name}"
+ end
+
+ def search_member
+ results = []
+
+ if params[:q].present?
+ uids = group.users.pluck(:id)
+ results = User
+ .where('email like ?', "#{params[:q]}%")
+ .where.not(id: uids) # Exclude group members
+ .limit(10)
+ end
+
+ render json: results.map { |r| Hash[:id, r.id, :email, r.email] }
+ end
+
+ private
+
+ def user
+ @user ||= User.find(params[:user_id])
+ end
+
+end
diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb
index ef98682..0727ae7 100644
--- a/app/helpers/breadcrumb_helper.rb
+++ b/app/helpers/breadcrumb_helper.rb
@@ -1,56 +1,56 @@
module BreadcrumbHelper
# Domain
# Domain / group / example.com
# Domain / group / example.com / ns1.example.com IN A
# Domain / group / example.com / new
def breadcrumbs(leaf)
crumbs = generate_crumbs_for(leaf)
crumbs.each { |c|
# Last element should not be a link
if c == crumbs.last || c[:link].nil?
yield c[:name]
else
yield link_to(c[:name], c[:link])
end
}
end
private
# rubocop:disable all
def generate_crumbs_for(leaf)
stack = []
crumbs = []
stack.push leaf if leaf
while crumb = stack.pop # rubocop:disable Lint/AssignmentInCondition
case crumb
when Record
if crumb.persisted?
crumbs.push(
name: "#{crumb.name} IN #{crumb.type}",
link: domain_record_path(crumb.domain_id, crumb))
else
crumbs.push(name: :new)
end
stack.push crumb.domain
when Domain
if crumb.persisted?
crumbs.push(name: crumb.name, link: domain_path(crumb))
else
crumbs.push(name: :new)
end
stack.push crumb.group
when Group
- crumbs.push(name: crumb.name)
+ crumbs.push(name: crumb.name, link: group_path(crumb))
end
end
crumbs.push(name: 'Domains', link: '/')
crumbs.reverse
end
# rubocop:enable all
end
diff --git a/app/views/domains/index.html.erb b/app/views/domains/index.html.erb
index fa9426c..f6d30d5 100644
--- a/app/views/domains/index.html.erb
+++ b/app/views/domains/index.html.erb
@@ -1,31 +1,31 @@
<table class="table table-striped">
<thead>
</thead>
<tbody>
<% @domains.group_by(&:group).each do |group, domains| %>
<tr>
- <th colspan="2"><%= group.name %></th>
+ <th colspan="2"><%= link_to group.name, group_path(group) %></th>
<th colspan="2">Controls</th>
</tr>
<% domains.each do |domain| %>
<tr>
<td><%= link_to domain.name, domain %></td>
<td>
<% if domain.reverse? %>
<abbr title="Reverse"><span class="glyphicon glyphicon-chevron-left"></span></abbr>
<% else %>
<abbr title="Forward"><span class="glyphicon glyphicon-chevron-right"></span></abbr>
<% end %>
</td>
<td><%= link_to 'Edit', edit_domain_path(domain) %></td>
<td><%= link_to 'Destroy', domain, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
<p>
<%= link_to 'New Domain &raquo;'.html_safe, new_domain_path, class: 'btn btn-lg btn-primary' %>
</p>
diff --git a/app/views/groups/show.html.erb b/app/views/groups/show.html.erb
new file mode 100644
index 0000000..8f0df1f
--- /dev/null
+++ b/app/views/groups/show.html.erb
@@ -0,0 +1,24 @@
+<table class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Members</th>
+ <th>Controls</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% @group.memberships.includes(:user).each do |membership| %>
+ <tr>
+ <td><%= membership.user.email %><%= " (you)" if current_user == membership.user %></td>
+ <td>
+ <%= link_to 'x', destroy_member_group_path(@group, membership.user_id), method: :delete %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<%= bootstrap_form_tag(url: create_member_group_path(@group), layout: :inline) do |f| %>
+ <%= f.text_field :email, prepend: 'Member', hide_label: true, id: 'js-search-member', data: { group: @group.id } %>
+ <%= f.submit 'Add', class: 'btn btn-primary' %>
+<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index b98876d..7ef49f0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,22 +1,31 @@
Rails.application.routes.draw do
# Override devise user removal
devise_scope :users do
delete :users, to: redirect('/')
end
devise_for :users
root to: redirect('/domains')
+ 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
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 } }
# rubocop:enable Style/AlignHash
end
end
end

Event Timeline