From daf469ce7f587e25e5af34c77f4b984af807a49c Mon Sep 17 00:00:00 2001 From: Adam Cooke Date: Tue, 27 Jul 2021 16:55:20 +0000 Subject: [PATCH] refactor: user management --- .../application/application.coffee | 1 - app/controllers/application_controller.rb | 15 +---- app/controllers/organizations_controller.rb | 3 +- app/controllers/servers_controller.rb | 1 - app/controllers/sessions_controller.rb | 1 - app/controllers/user_controller.rb | 1 - app/controllers/users_controller.rb | 58 ++++++++--------- app/models/organization.rb | 14 ---- app/models/organization_user.rb | 39 ----------- app/models/server.rb | 4 -- app/models/user.rb | 32 +--------- app/views/app_mailer/new_user.text.erb | 12 ---- app/views/app_mailer/user_invite.text.erb | 10 --- .../app_mailer/verify_email_address.text.erb | 14 ---- app/views/layouts/application.html.haml | 14 ++-- app/views/organizations/_nav.html.haml | 20 +++--- app/views/servers/_settings_header.html.haml | 3 +- app/views/servers/_sidebar.html.haml | 3 +- app/views/user/join.html.haml | 16 ----- app/views/user/new.html.haml | 41 ------------ app/views/user/verify.html.haml | 18 ------ app/views/users/_form.html.haml | 48 ++++++++++---- app/views/users/edit.html.haml | 5 +- app/views/users/index.html.haml | 64 ++++--------------- app/views/users/new.html.haml | 11 ++-- config/application.rb | 3 - config/routes.rb | 14 ++-- 27 files changed, 106 insertions(+), 359 deletions(-) delete mode 100644 app/views/app_mailer/new_user.text.erb delete mode 100644 app/views/app_mailer/user_invite.text.erb delete mode 100644 app/views/app_mailer/verify_email_address.text.erb delete mode 100644 app/views/user/join.html.haml delete mode 100644 app/views/user/new.html.haml delete mode 100644 app/views/user/verify.html.haml diff --git a/app/assets/javascripts/application/application.coffee b/app/assets/javascripts/application/application.coffee index b13efb0..2ad8eaf 100644 --- a/app/assets/javascripts/application/application.coffee +++ b/app/assets/javascripts/application/application.coffee @@ -62,7 +62,6 @@ $ -> else $('[data-credential-key-type=all]').show() - $(document).on 'change', 'select#credential_type', -> value = $(this).val() toggleCredentialInputs(value) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 410f698..79b46b5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,7 +5,6 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :login_required - before_action :verified_email_required before_action :set_timezone rescue_from Authie::Session::InactiveSession, :with => :auth_session_error @@ -23,25 +22,13 @@ class ApplicationController < ActionController::Base def admin_required if logged_in? unless current_user.admin? - render :text => "Not permitted" + render :plain => "Not permitted" end else redirect_to login_path(:return_to => request.fullpath) end end - def verified_email_required - if logged_in? && !current_user.verified? - redirect_to verify_path(:return_to => request.fullpath) - end - end - - def require_organization_admin - unless organization.admin?(current_user) - redirect_to organization_root_path(organization), :alert => "This page can only be accessed by the organization admins" - end - end - def require_organization_owner unless organization.owner == current_user redirect_to organization_root_path(organization), :alert => "This page can only be accessed by the organization's owner (#{organization.owner.name})" diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb index ada4e96..2afc012 100644 --- a/app/controllers/organizations_controller.rb +++ b/app/controllers/organizations_controller.rb @@ -1,7 +1,6 @@ class OrganizationsController < ApplicationController - before_action :admin_required, :only => [:new, :create] - before_action :require_organization_admin, :only => [:edit, :update, :delete, :destroy] + before_action :admin_required, :only => [:new, :create, :delete, :destroy] def index if current_user.admin? diff --git a/app/controllers/servers_controller.rb b/app/controllers/servers_controller.rb index dd759f9..ba0f7ec 100644 --- a/app/controllers/servers_controller.rb +++ b/app/controllers/servers_controller.rb @@ -2,7 +2,6 @@ class ServersController < ApplicationController include WithinOrganization - before_action :require_organization_admin, :only => [:new, :create, :delete, :destroy] before_action :admin_required, :only => [:advanced, :suspend, :unsuspend] before_action { params[:id] && @server = organization.servers.present.find_by_permalink!(params[:id]) } diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index c40602f..59a29dd 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -3,7 +3,6 @@ class SessionsController < ApplicationController layout 'sub' skip_before_action :login_required, :only => [:new, :create, :create_with_token, :begin_password_reset, :finish_password_reset, :ip, :raise_error] - skip_before_action :verified_email_required def create login(User.authenticate(params[:email_address], params[:password])) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 897ff66..c2b622d 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -1,7 +1,6 @@ class UserController < ApplicationController skip_before_action :login_required, :only => [:new, :create, :join] - skip_before_action :verified_email_required, :only => [:edit, :update, :verify] def new @user_invite = UserInvite.active.find_by!(:uuid => params[:invite_token]) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index c471797..fdc0d0e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,63 +1,55 @@ class UsersController < ApplicationController - include WithinOrganization - before_action :require_organization_admin - before_action :require_organization_owner, :only => [:make_owner] - before_action { params[:id] && @user = params[:invite].present? ? organization.user_invites.find_by_uuid!(params[:id]) : organization.users.find_by_uuid!(params[:id]) } + + before_action :admin_required + before_action { params[:id] && @user = User.find_by!(uuid: params[:id]) } def index - @users = organization.organization_users.where(:user_type => 'User').includes(:user).to_a.sort_by { |u| "#{u.user.first_name}#{u.user.last_name}".upcase } - @pending_users = organization.organization_users.where(:user_type => "UserInvite").includes(:user).to_a.sort_by { |u| u.user.email_address.upcase } + @users = User.order(:first_name, :last_name).includes(:organization_users) end def new - @organization_user = organization.organization_users.build + @user = User.new(admin: true) end def create - @organization_user = organization.organization_users.build(params.require(:organization_user).permit(:email_address, :admin, :all_servers)) - if @organization_user.save - AppMailer.user_invite(@organization_user.user, organization).deliver - redirect_to_with_json [organization, :users], :notice => "An invitation will be sent to #{@organization_user.user.email_address} which will allow them to access your organization." + @user = User.new(params.require(:user).permit(:email_address, :first_name, :last_name, :password, :password_confirmation, :admin, organization_ids: [])) + if @user.save + redirect_to_with_json :users, :notice => "#{@user.name} has been created successfully." else - render_form_errors 'new', @organization_user + render_form_errors 'new', @user end end def edit - @organization_user = organization.user_assignment(@user) end def update - @organization_user = organization.user_assignment(@user) - if @organization_user.update(params.require(:organization_user).permit(:admin)) - redirect_to_with_json [organization, :users], :notice => "Permissions for #{@organization_user.user.name} have been updated successfully." + @user.attributes = params.require(:user).permit(:email_address, :first_name, :last_name, :admin, organization_ids: []) + + if @user == current_user && !@user.admin? + respond_to do |wants| + wants.html { redirect_to users_path, alert: "You cannot change your own admin status" } + wants.json { render :json => {:form_errors => ["You cannot change your own admin status"]}, :status => 422 } + end + return + end + + if @user.save + redirect_to_with_json :users, :notice => "Permissions for #{@user.name} have been updated successfully." else - render_form_errors 'edit', @organization_user + render_form_errors 'edit', @user end end def destroy if @user == current_user - redirect_to_with_json [organization, :users], :alert => "You cannot revoke your own access." + redirect_to_with_json :users, :alert => "You cannot delete your own user." return end - if @user == organization.owner - redirect_to_with_json [organization, :users], :alert => "You cannot revoke the organization owner's access." - return - end - - organization.organization_users.where(:user => @user).destroy_all - redirect_to_with_json [organization, :users], :notice => "#{@user.name} has been removed from this organization" + @user.destroy! + redirect_to_with_json :users, :notice => "#{@user.name} has been removed" end - def make_owner - if @user.is_a?(User) - organization.make_owner(@user) - redirect_to_with_json [organization, :users], :notice => "#{@user.name} is now the owner of this organization." - else - raise Postal::Error, "User must be a User not a UserInvite to make owner" - end - end end diff --git a/app/models/organization.rb b/app/models/organization.rb index bfdfd40..4f6f125 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -69,20 +69,6 @@ class Organization < ApplicationRecord suspended_at.present? end - def admin?(user) - user.admin? || - !!(owner?(user) || user_assignment(user)&.admin?) - end - - def owner?(user) - self.owner == user - end - - def accessible_by?(user) - user.admin? || - !!(user_assignment(user)) - end - def user_assignment(user) @user_assignments ||= {} @user_assignments[user.id] ||= organization_users.where(:user => user).first diff --git a/app/models/organization_user.rb b/app/models/organization_user.rb index 1da0b3d..08a7545 100644 --- a/app/models/organization_user.rb +++ b/app/models/organization_user.rb @@ -16,43 +16,4 @@ class OrganizationUser < ApplicationRecord belongs_to :organization belongs_to :user, :polymorphic => true, :optional => true - validate :validate_uniqueness - - before_create :create_user_invite - after_destroy :remove_user_invites - - def email_address - @email_address ||= user&.email_address - end - - def email_address=(value) - @email_address = value - end - - def create_user_invite - if self.user.nil? - user = UserInvite.where(:email_address => @email_address).first_or_initialize - if user.save - self.user = user - else - errors.add :base, user.errors.full_messages.to_sentence - throw :abort - end - end - end - - def validate_uniqueness - if self.email_address.present? - if organization.organization_users.where.not(:id => self.id).any? { |ou| ou.user.email_address.upcase == self.email_address.upcase } - errors.add :email_address, "is already assigned or has an pending invite" - end - end - end - - def remove_user_invites - if self.user.is_a?(UserInvite) && self.user.organizations.empty? - self.user.destroy - end - end - end diff --git a/app/models/server.rb b/app/models/server.rb index 2bddb47..53c4649 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -119,10 +119,6 @@ class Server < ApplicationRecord end end - def accessible_by?(user) - organization.accessible_by?(user) - end - def to_param permalink end diff --git a/app/models/user.rb b/app/models/user.rb index 93145b0..6e03a2f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,7 +31,7 @@ class User < ApplicationRecord validates :first_name, :presence => true validates :last_name, :presence => true - validates :email_address, :presence => true, :uniqueness => true, :format => {:with => /@/} + validates :email_address, :presence => true, :uniqueness => true, :format => {:with => /@/, allow_blank: true} validates :time_zone, :presence => true default_value :time_zone, -> { 'UTC' } @@ -39,23 +39,6 @@ class User < ApplicationRecord has_many :organization_users, :dependent => :destroy, :as => :user has_many :organizations, :through => :organization_users - scope :verified, -> { where.not(:email_verified_at => nil) } - - when_attribute :email_address, :changes_to => :anything do - before_save do |was, now| - unless self.new_record? && self.email_verified_at - self.email_verification_token = rand(999999).to_s.rjust(6, '0') - self.email_verified_at = nil - end - end - - after_commit do |was, new| - if self.email_verified_at.nil? && was.present? - AppMailer.verify_email_address(self).deliver - end - end - end - def organizations_scope @organizations_scope ||= begin if self.admin? @@ -74,15 +57,6 @@ class User < ApplicationRecord uuid end - def verify! - self.email_verified_at = Time.now - self.save! - end - - def verified? - email_verified_at.present? - end - def md5_for_gravatar @md5_for_gravatar ||= Digest::MD5.hexdigest(email_address.to_s.downcase) end @@ -95,10 +69,6 @@ class User < ApplicationRecord "#{name} <#{email_address}>" end - def generate_login_token - JWT.encode({'user' => self.id, 'timestamp' => Time.now.to_f}, Postal.signing_key.to_s, 'HS256') - end - def self.[](email) where(:email_address => email).first end diff --git a/app/views/app_mailer/new_user.text.erb b/app/views/app_mailer/new_user.text.erb deleted file mode 100644 index f7b7cd3..0000000 --- a/app/views/app_mailer/new_user.text.erb +++ /dev/null @@ -1,12 +0,0 @@ -Hello <%= @user.first_name %>, - -To verify your e-mail address you will be prompted to enter a code when you login to your Postal account. The code you need to enter is: - -<%= @user.email_verification_token %> - -Once you've done that, you'll be able to access your account. - -Thanks, - -<%= Postal.smtp_from_name %> -<%= Postal.smtp_from_address %> diff --git a/app/views/app_mailer/user_invite.text.erb b/app/views/app_mailer/user_invite.text.erb deleted file mode 100644 index 1523285..0000000 --- a/app/views/app_mailer/user_invite.text.erb +++ /dev/null @@ -1,10 +0,0 @@ -You've been invited to access the <%= @organization.name %> organization on Postal. - -To accept this invitation, please click the link below to create an account or login to an existing one. - -<%= Postal.host_with_protocol %>/join/<%= @user_invite.uuid %> - -Thanks, - -<%= Postal.smtp_from_name %> -<%= Postal.smtp_from_address %> diff --git a/app/views/app_mailer/verify_email_address.text.erb b/app/views/app_mailer/verify_email_address.text.erb deleted file mode 100644 index 22de9ad..0000000 --- a/app/views/app_mailer/verify_email_address.text.erb +++ /dev/null @@ -1,14 +0,0 @@ -Hi <%= @user.first_name %>, - -You've just changed the e-mail address on your Postal account. So that we can verify that you own the new address you've entered, we need you to enter the code below into the box shown in your web browser. - -<%= @user.email_verification_token %> - -If you don't have a box on your screen, just login to your Postal account to continue. - -<%= Postal.host_with_protocol %>/login - -Thanks, - -<%= Postal.smtp_from_name %> -<%= Postal.smtp_from_address %> diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 2ab4239..b0d3ae5 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -29,18 +29,20 @@ %li.siteHeader__navItem.siteHeader__navItem--organization = link_to organization.name, organization_root_path(organization), :class => 'siteHeader__navLinkWithMenu' %ul.siteHeader__subMenu - %li.siteHeader__subMenuItem.siteHeader__subMenuItem--header= link_to organization.name, organization_settings_path(organization) - - if organization.admin?(current_user) - %li.siteHeader__subMenuItem= link_to "Organization Settings", organization_settings_path(organization), :class => 'siteHeader__subMenuLink' - %li.siteHeader__subMenuItem= link_to "Manage Users", organization_users_path(organization), :class => 'siteHeader__subMenuLink' + %li.siteHeader__subMenuItem.siteHeader__subMenuItem--header= link_to organization.name, organization_root_path(organization) + %li.siteHeader__subMenuItem= link_to "Mail servers", organization_root_path(organization), :class => 'siteHeader__subMenuLink' + %li.siteHeader__subMenuItem= link_to "Domains", organization_domains_path(organization), :class => 'siteHeader__subMenuLink' + %li.siteHeader__subMenuItem= link_to "Organization Settings", organization_settings_path(organization), :class => 'siteHeader__subMenuLink' - if current_user.admin? %li.siteHeader__subMenuItem= link_to "Create new organization", :new_organization, :class => 'siteHeader__subMenuLink' - if current_user.organizations.present.count > 1 %li.siteHeader__subMenuItem= link_to "Switch organization", root_path, :class => 'siteHeader__subMenuLink' %li.siteHeader__navItem.siteHeader__navItem--user= current_user.name %li.siteHeader__navItem= link_to "My Settings", settings_path, :class => 'sideHeader__navItemLink' - - if current_user.admin? && Postal.ip_pools? - %li.siteHeader__navItem= link_to "IP Pools", ip_pools_path, :class => 'sideHeader__navItemLink' + - if current_user.admin? + - if Postal.ip_pools? + %li.siteHeader__navItem= link_to "IP Pools", ip_pools_path, :class => 'sideHeader__navItemLink' + %li.siteHeader__navItem= link_to "Users", users_path, :class => 'sideHeader__navItemLink' %li.siteHeader__navItem= link_to "Logout", logout_path, :method => :delete, :class => 'sideHeader__navItemLink' .siteContent diff --git a/app/views/organizations/_nav.html.haml b/app/views/organizations/_nav.html.haml index 77c834a..379809b 100644 --- a/app/views/organizations/_nav.html.haml +++ b/app/views/organizations/_nav.html.haml @@ -1,11 +1,9 @@ -- if organization.admin?(current_user) - .navBar - %ul - %li.navBar__item= link_to "Mail Servers", organization_root_path(organization), :class => ['navBar__link', active_nav == :servers ? 'is-active' : ''] - %li.navBar__item= link_to "Domains", organization_domains_path(organization), :class => ['navBar__link', active_nav == :domains ? 'is-active' : ''] - %li.navBar__item= link_to "Settings", organization_settings_path(organization), :class => ['navBar__link', active_nav == :settings ? 'is-active' : ''] - - if Postal.ip_pools? - %li.navBar__item= link_to "IPs", organization_ip_pools_path(organization), :class => ['navBar__link', active_nav == :ips ? 'is-active' : ''] - %li.navBar__item= link_to "Users", organization_users_path(organization), :class => ['navBar__link', active_nav == :users ? 'is-active' : ''] - - if organization.owner?(current_user) - %li.navBar__item= link_to "Delete Organization", organization_delete_path(organization), :class => ['navBar__link', active_nav == :delete ? 'is-active' : ''] +.navBar + %ul + %li.navBar__item= link_to "Mail Servers", organization_root_path(organization), :class => ['navBar__link', active_nav == :servers ? 'is-active' : ''] + %li.navBar__item= link_to "Domains", organization_domains_path(organization), :class => ['navBar__link', active_nav == :domains ? 'is-active' : ''] + %li.navBar__item= link_to "Settings", organization_settings_path(organization), :class => ['navBar__link', active_nav == :settings ? 'is-active' : ''] + - if Postal.ip_pools? + %li.navBar__item= link_to "IPs", organization_ip_pools_path(organization), :class => ['navBar__link', active_nav == :ips ? 'is-active' : ''] + - if current_user.admin? + %li.navBar__item= link_to "Delete Organization", organization_delete_path(organization), :class => ['navBar__link', active_nav == :delete ? 'is-active' : ''] diff --git a/app/views/servers/_settings_header.html.haml b/app/views/servers/_settings_header.html.haml index b235654..cd7ebd2 100644 --- a/app/views/servers/_settings_header.html.haml +++ b/app/views/servers/_settings_header.html.haml @@ -8,5 +8,4 @@ %li.navBar__item= link_to "IP Rules", [organization, @server, :ip_pool_rules], :class => ['navBar__link', active_nav == :ip_pool_rules ? 'is-active' : ''] - if current_user.admin? %li.navBar__item= link_to "Advanced Settings", [:advanced, organization, @server], :class => ['navBar__link', active_nav == :admin ? 'is-active' : ''] - - if organization.admin?(current_user) - %li.navBar__item= link_to "Delete", [:delete, organization, @server], :class => ['navBar__link', active_nav == :delete ? 'is-active' : ''] + %li.navBar__item= link_to "Delete", [:delete, organization, @server], :class => ['navBar__link', active_nav == :delete ? 'is-active' : ''] diff --git a/app/views/servers/_sidebar.html.haml b/app/views/servers/_sidebar.html.haml index 3ba2ed4..400794a 100644 --- a/app/views/servers/_sidebar.html.haml +++ b/app/views/servers/_sidebar.html.haml @@ -13,5 +13,4 @@ %p.sidebarServerList__mode.label{:class => "label--serverStatus-#{server.status.underscore}"}= t("server_statuses.#{server.status.underscore}") %p.sidebarServerList__title= server.name %p.sidebarServerList__quantity #{number_with_precision server.message_rate, :precision => 2} messages/minute - - if organization.admin?(current_user) - %p.sidebar__new= link_to "Build a new mail server", [:new, organization, :server] + %p.sidebar__new= link_to "Build a new mail server", [:new, organization, :server] diff --git a/app/views/user/join.html.haml b/app/views/user/join.html.haml deleted file mode 100644 index 910b53c..0000000 --- a/app/views/user/join.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -- page_title << "Join Organization" -.pageHeader - %h1.pageHeader__title - Join Organization -.pageContent.pageContent--compact - %h2.pageContent__intro.u-margin - Welcome to Postal. - - if @organizations.size == 1 - You've been invited to join the #{@organizations.first.name} organization. Once accepted, you'll be able to - access this organization's mail servers. - - else - You've been invited to join an organization - - %p.buttonSet - = link_to "Accept " + (@organizations.size == 1 ? "Invitation" : "Invitations"), '', :class => "button button--positive", :remote => true, :method => :post - = link_to "Reject " + (@organizations.size == 1 ? "Invitation" : "Invitations"), '', :class => "button button--danger", :remote => true, :method => :delete diff --git a/app/views/user/new.html.haml b/app/views/user/new.html.haml deleted file mode 100644 index 9365bd4..0000000 --- a/app/views/user/new.html.haml +++ /dev/null @@ -1,41 +0,0 @@ -- @wide = true -- page_title << "Signup" -.subPageBox__title - Join the #{@user_invite.organizations.first.name} organization -= display_flash - -.subPageBox__content - %p.subPageBox__text - If you don't already have an account on this system, you can create one below. Otherwise, you should - #{link_to "login to your existing account", login_path(:return_to => join_path(@user_invite.uuid)), :class => 'u-link'} - and add this organization to that. - - .signupForm - = form_for @user, :url => signup_path do |f| - = hidden_field_tag 'return_to', params[:return_to] - = hidden_field_tag 'invite_token', params[:invite_token] - = f.error_messages - .fieldSet.fieldSet--compact.u-margin - .fieldSet__fieldPair - .fieldSet__field - = f.label :first_name, :class => 'fieldSet__label' - .fieldSet__input= f.text_field :first_name, :class => 'input input--text input--onWhite', :autofocus => true - .fieldSet__field - = f.label :last_name, :class => 'fieldSet__label' - .fieldSet__input= f.text_field :last_name, :class => 'input input--text input--onWhite' - .fieldSet__field - = f.label :email_address, :class => 'fieldSet__label' - .fieldSet__input= f.text_field :email_address, :class => 'input input--text input--onWhite' - .fieldSet__fieldPair - .fieldSet__field - = f.label :password, :class => 'fieldSet__label' - .fieldSet__input= f.password_field :password, :class => 'input input--text input--onWhite', :placeholder => '•••••••••••' - .fieldSet__field - = f.label :password_confirmation, " ".html_safe, :class => 'fieldSet__label' - .fieldSet__input= f.password_field :password_confirmation, :class => 'input input--text input--onWhite', :placeholder => '•••••••••••' - - .loginForm__submit - %ul.loginForm__links - %li= link_to "Back to login", login_path(:return_to => params[:return_to]) - %p= submit_tag "Create Account", :class => 'button button--positive', :tabindex => 3 - diff --git a/app/views/user/verify.html.haml b/app/views/user/verify.html.haml deleted file mode 100644 index dbcdcaa..0000000 --- a/app/views/user/verify.html.haml +++ /dev/null @@ -1,18 +0,0 @@ -- page_title << "Verify your e-mail address" -.pageHeader - %h1.pageHeader__title - Please verify your e-mail address -.pageContent.pageContent--compact - %h2.pageContent__intro.u-margin - We need to verify that you're the owner of the e-mail address on your account. It is currently #{current_user.email_address}. To - do this, we've sent you an e-mail with a 6-digit code. Please check your e-mail and enter the code within in the box below. - %p.pageContent__text - If you need to change your e-mail address, you can do this in from your #{link_to 'settings page', settings_path, :class => "u-link"}. - If you haven't received the e-mail, you can #{link_to 'click here to resend it', '', :class => "u-link"}. - = form_tag request.fullpath, :remote => true do - = hidden_field_tag 'return_to', params[:return_to] - %p.u-margin - = text_field_tag "code", params[:code], :autofocus => true, :class => 'input input--text js-multibox' - .buttonSet.u-center - = submit_tag "Verify my e-mail address", :class => 'button button--positive js-form-submit' - diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml index b512d3a..0011fb1 100644 --- a/app/views/users/_form.html.haml +++ b/app/views/users/_form.html.haml @@ -1,24 +1,44 @@ -= form_for @organization_user, :url => @organization_user.new_record? ? organization_users_path(organization) : organization_user_path(organization, @organization_user.user), :remote => true do |f| += form_for @user, :url => @user.new_record? ? users_path : user_path(@user), :remote => true do |f| = f.error_messages - = hidden_field_tag 'invite', params[:invite] - %fieldset.fieldSet + .fieldSet + .fieldSet__title + Enter user details + .fieldSet__field + = f.label :first_name, :class => 'fieldSet__label' + .fieldSet__input= f.text_field :first_name, :class => 'input input--text', :autofocus => true + .fieldSet__field + = f.label :last_name, :class => 'fieldSet__label' + .fieldSet__input= f.text_field :last_name, :class => 'input input--text' .fieldSet__field = f.label :email_address, :class => 'fieldSet__label' - .fieldSet__input - = f.text_field :email_address, :autofocus => true, :class => 'input input--text', :disabled => @organization_user.persisted? + .fieldSet__input= f.text_field :email_address, :class => 'input input--text', autocomplete: 'one-time-code' + - unless @user.persisted? + .fieldSet__field + = f.label :password, :class => 'fieldSet__label' + .fieldSet__input= f.password_field :password, :class => 'input input--text', :placeholder => '•••••••••••', autocomplete: 'one-time-code' + .fieldSet__field + = f.label :password_confirmation, "Confirm".html_safe, :class => 'fieldSet__label' + .fieldSet__input= f.password_field :password_confirmation, :class => 'input input--text', :placeholder => '•••••••••••', autocomplete: 'one-time-code' + + %fieldset.fieldSet .fieldSet__title What level of access do you wish to grant? + .fieldSet__titleSubText + Admin users have full access to all organizations and settings. Non-admin users will only + have access to the organizations that you select here. .fieldSet__field - = f.label :admin, :class => 'fieldSet__label' + .fieldSet__label Admin? .fieldSet__input - = f.select :admin, [["No - do not grant admin access", false], ["Yes - grant admin access", true]], {},:class => 'input input--select' - %p.fieldSet__text - Users who have admin access will be permitted to manage the organization as if they had the same - access as the organization owner. This includes managing users, creating & deleting mail servers, - and even removing the account. This level of access should granted carefully. - Regardless of which level you select, this user will have access to all servers within the organization. + = hidden_field_tag 'user[organization_ids][]' + = f.select :admin, [["Yes - grant admin access", true], ["No - do not grant admin access", false]], {},:class => 'input input--select fieldSet__checkboxListAfter js-checkbox-list-toggle' + %ul.checkboxList{:class => [@user.admin? ? 'is-hidden' : '']} + - for org in Organization.order(:name).to_a + %li.checkboxList__item + .checkboxList__checkbox= check_box_tag "user[organization_ids][]", org.id, @user.organizations.include?(org), :id => "org_#{org.id}" + .checkboxList__label + = label_tag "org_#{org.id}", org.name, :class => 'checkboxList__actualLabel' .fieldSetSubmit.buttonSet - = submit_tag @organization_user.new_record? ? "Add User" : "Save User", :class => 'button button--positive js-form-submit' + = submit_tag @user.new_record? ? "Add User" : "Save User", :class => 'button button--positive js-form-submit' .fieldSetSubmit__delete - = link_to "Back to user list", [organization, :users], :class => 'button button--neutral' + = link_to "Back to user list", :users, :class => 'button button--neutral' diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 6a6a612..e4a82aa 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -3,13 +3,10 @@ .pageHeader %h1.pageHeader__title %span.pageHeader__titlePrevious - = @organization.name - → - Users + = link_to 'Users', users_path → Edit user permissions -= render 'organizations/nav', :active_nav => :users .pageContent.pageContent--compact = render 'form' diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml index 8507a4a..73c28f3 100644 --- a/app/views/users/index.html.haml +++ b/app/views/users/index.html.haml @@ -1,57 +1,21 @@ - page_title << "Users" .pageHeader %h1.pageHeader__title - %span.pageHeader__titlePrevious - = @organization.name - → Users -= render 'organizations/nav', :active_nav => :users .pageContent.pageContent--compact - - if @users.empty? && @pending_users.empty? - .noData.noData--clean - %p.noData__title There are no users assigned to this organization. - %p.noData__text - You add additional users that will be permitted to access this organization. - They will be sent an email and they'll be able to create an account which will - allow them to login and access this organization. - %p.noData__button.buttonSet.buttonSet--center - = link_to "Invite the first user", [:new, organization, :user], :class => 'button button--positive' + %ul.userList.u-margin + - for user in @users + %li.userList__item + = image_tag user.avatar_url, :class => 'userList__avatar' + .userList__details + %p.userList__name + = user.name + - if user.admin? + %span.userList__admin.label Admin + %p.userList__email= user.email_address + %ul.userList__actions + %li= link_to "Edit permissions", [:edit, user] + %li= link_to "Delete user", user, :method => :delete, :data => {:confirm => "Are you sure you wish to revoke #{user.name}'s access?", :disable_with => "Deleting..."}, :remote => true, :class => 'userList__revoke' - - else - %p.pageContent__intro.u-margin - You can share access to this organization with other people by adding them - here. They'll need to create their own account first and then you'll be able - to add them to your organization by entering their e-mail address. - - %ul.userList.u-margin - - for user in @users - %li.userList__item - = image_tag user.user.avatar_url, :class => 'userList__avatar' - .userList__details - %p.userList__name - = user.user.name - - if user.user == organization.owner - %span.userList__owner.label Owner - - elsif user.admin? - %span.userList__admin.label Admin - %p.userList__email= user.user.email_address - %ul.userList__actions - - if organization.owner != user.user - %li= link_to "Edit permissions", [:edit, organization, user.user] - - if organization.owner == current_user - %li= link_to "Make owner", [:make_owner, organization, user.user], :method => :post, :data => {:confirm => "Are you sure you wish to make #{user.user.name} the owner of this organization? They will be granted full admin access. You won't be able to change this back.", :disable_with => "Promoting..."}, :remote => true - %li= link_to "Revoke access", [organization, user.user], :method => :delete, :data => {:confirm => "Are you sure you wish to revoke #{user.user.name}'s access to the organization?", :disable_with => "Deleting..."}, :remote => true, :class => 'userList__revoke' - - for user in @pending_users - %li.userList__item - = image_tag user.user.avatar_url, :class => 'userList__avatar' - .userList__details - %p.userList__name - = user.user.email_address - %span.userList__pending.label Pending - %ul.userList__actions - %li= link_to "Edit permissions", edit_organization_user_path(organization, user.user, :invite => 1) - %li= link_to "Cancel invitation", organization_user_path(organization, user.user, :invite => 1), :method => :delete, :data => {:confirm => "Are you sure you wish to cancel this invitation?", :disable_with => "Deleting..."}, :remote => true, :class => 'userList__revoke' - - - %p.u-center= link_to "Invite a new user", [:new, organization, :user], :class => 'button button--positive' + %p.u-center= link_to "Add a new user", :new_user, :class => 'button button--positive' diff --git a/app/views/users/new.html.haml b/app/views/users/new.html.haml index c075224..86be6f0 100644 --- a/app/views/users/new.html.haml +++ b/app/views/users/new.html.haml @@ -3,17 +3,14 @@ .pageHeader %h1.pageHeader__title %span.pageHeader__titlePrevious - = @organization.name - → - Users + = link_to 'Users', :users → Add user -= render 'organizations/nav', :active_nav => :users .pageContent.pageContent--compact %p.pageContent__intro.u-margin - To add someone to your organization enter their e-mail address below. If - they don't already have a Postal account, they'll need to create one - before you can add them to your account. + To add someone to this Postal installation, you can add them below. You'll need to + choose whether to make them an admin (full access to all organizations and settings) + or whether you wish to limit them to specific organizations. = render 'form' diff --git a/config/application.rb b/config/application.rb index f49c023..dc53555 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,9 +14,6 @@ Bundler.require(*Rails.groups) module Postal class Application < Rails::Application - # Set the Rails logger - config.logger = Postal.logger_for(:rails) - # Disable most generators config.generators do |g| g.orm :active_record diff --git a/config/routes.rb b/config/routes.rb index 7e7523d..d0a4f18 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -56,9 +56,7 @@ Rails.application.routes.draw do post :suspend, :on => :member post :unsuspend, :on => :member end - resources :users do - post :make_owner, :on => :member - end + resources :ip_pool_rules resources :ip_pools, :controller => 'organization_ip_pools' do put :assignments, :on => :collection @@ -71,6 +69,7 @@ Rails.application.routes.draw do end resources :organizations, :except => [:index] + resources :users resources :ip_pools do resources :ip_addresses end @@ -79,16 +78,15 @@ Rails.application.routes.draw do patch 'settings' => 'user#update' post 'persist' => 'sessions#persist' - match 'verify' => 'user#verify', :via => [:get, :post] - get 'signup/:invite_token' => 'user#new', :as => 'new_signup' - post 'signup' => 'user#create' - match 'join/:token' => 'user#join', :via => [:get, :post, :delete], :as => 'join' get 'login' => 'sessions#new' post 'login' => 'sessions#create' get 'login/token' => 'sessions#create_with_token' delete 'logout' => 'sessions#destroy' match 'login/reset' => 'sessions#begin_password_reset', :via => [:get, :post] match 'login/reset/:token' => 'sessions#finish_password_reset', :via => [:get, :post] - root 'organizations#index' + + get 'ip' => 'sessions#ip' + + root 'organizations#index' end