diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 38e4c7e..67b4574 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,48 +1,49 @@ // 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/SRV record only $('#record_type').change(function() { if ($(this).val() == 'MX' || $(this).val() == 'SRV') { $('#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'), + datumTokenizer: Bloodhound.tokenizers.obj.whitespace('email'), queryTokenizer: Bloodhound.tokenizers.whitespace, + identify: function(obj) { return obj.id; }, 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/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb new file mode 100644 index 0000000..fb43640 --- /dev/null +++ b/app/controllers/admin/groups_controller.rb @@ -0,0 +1,56 @@ +module Admin + class GroupsController < ApplicationController + before_action :authenticate_user! + before_action :admin_only! + + before_action :group, only: [:edit, :update, :destroy] + + # GET /groups + def index + @groups = Group.all + @membership_count = Membership.group(:group_id).count + @domain_count = Domain.group(:group_id).count + end + + # GET /groups/new + def new + @group = Group.new + end + + # GET /groups/1/edit + def edit + end + + # POST /groups + def create + @group = Group.new(group_params) + + if @group.save + redirect_to @group, notice: "#{@group.name} was successfully created." + else + render :new + end + end + + # PATCH/PUT /groups/1 + def update + if @group.update(group_params) + redirect_to admin_groups_url, notice: "#{@group.name} was successfully updated." + else + render :edit + end + end + + # DELETE /groups/1 + def destroy + @group.destroy + redirect_to admin_groups_url, notice: "#{@group.name} was successfully destroyed." + end + + private + + def group_params + params.require(:group).permit(:name) + end + end +end diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb index 84d4997..8330b7c 100644 --- a/app/helpers/breadcrumb_helper.rb +++ b/app/helpers/breadcrumb_helper.rb @@ -1,56 +1,60 @@ 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, link: group_path(crumb)) + if crumb.persisted? + crumbs.push(name: crumb.name, link: group_path(crumb)) + else + crumbs.push(name: :new) + end end end crumbs.push(name: glyph(:home), link: '/') crumbs.reverse end # rubocop:enable all end diff --git a/app/views/admin/groups/_form.html.erb b/app/views/admin/groups/_form.html.erb new file mode 100644 index 0000000..18585dc --- /dev/null +++ b/app/views/admin/groups/_form.html.erb @@ -0,0 +1,4 @@ +<%= bootstrap_form_for([:admin, @group], layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-4') do |f| %> + <%= f.text_field :name %> + <%= f.submit 'Save', class: 'btn btn-primary col-sm-offset-2' %> +<% end %> diff --git a/app/views/admin/groups/edit.html.erb b/app/views/admin/groups/edit.html.erb new file mode 100644 index 0000000..dfa41b1 --- /dev/null +++ b/app/views/admin/groups/edit.html.erb @@ -0,0 +1,3 @@ +

<%= @group.name %>

+ +<%= render 'form' %> diff --git a/app/views/admin/groups/index.html.erb b/app/views/admin/groups/index.html.erb new file mode 100644 index 0000000..8641bd8 --- /dev/null +++ b/app/views/admin/groups/index.html.erb @@ -0,0 +1,26 @@ + + + + + + + + + + + + <% @groups.each do |group| %> + + + + + + + + <% end %> + +
NameDomainsUsersControls
<%= link_to group.name, group %><%= @domain_count[group.id] || 0 %><%= @membership_count[group.id] || 0 %><%= link_to_edit edit_admin_group_path(group) %><%= link_to_destroy admin_group_path(group), method: :delete, data: { confirm: 'Are you sure?' } %>
+ +

+ <%= link_to 'New Group »'.html_safe, new_admin_group_path, class: 'btn btn-lg btn-primary' %> +

diff --git a/app/views/admin/groups/new.html.erb b/app/views/admin/groups/new.html.erb new file mode 100644 index 0000000..6b96f2e --- /dev/null +++ b/app/views/admin/groups/new.html.erb @@ -0,0 +1,3 @@ +

New Group

+ +<%= render 'form' %> diff --git a/app/views/groups/show.html.erb b/app/views/groups/show.html.erb index 1c1bcdd..e3950e3 100644 --- a/app/views/groups/show.html.erb +++ b/app/views/groups/show.html.erb @@ -1,24 +1,31 @@ +<% content_for :more_breadcrumbs do %> +
  • + <%= link_to_edit edit_admin_group_path(@group) %> + <%= link_to_destroy admin_group_path(@group), method: :delete, data: { confirm: 'Are you sure?' } %> +
  • +<% end if admin? %> + <% @group.memberships.includes(:user).each do |membership| %> <% end %>
    Members Controls
    <%= membership.user.email %><%= " (you)" if current_user == membership.user %> <%= link_to_destroy destroy_member_group_path(@group, membership.user_id), method: :delete %>
    <%= 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 11badcc..8281d12 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,35 +1,38 @@ 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 # Admin namespace :admin do + root to: redirect('/admin/groups') + + resources :groups, except: [:show] end end