diff --git a/app/assets/javascripts/discourse/controllers/invite.js.es6 b/app/assets/javascripts/discourse/controllers/invite.js.es6
index 965d4128d..6adc0f020 100644
--- a/app/assets/javascripts/discourse/controllers/invite.js.es6
+++ b/app/assets/javascripts/discourse/controllers/invite.js.es6
@@ -21,6 +21,7 @@ export default ObjectController.extend(ModalFunctionality, {
     if (this.get('saving')) return true;
     if (this.blank('email')) return true;
     if (!Discourse.Utilities.emailValid(this.get('email'))) return true;
+    if (this.get('model.details.can_invite_to')) return false;
     if (this.get('isPrivateTopic') && this.blank('groupNames')) return true;
     return false;
   }.property('email', 'isPrivateTopic', 'groupNames', 'saving'),
diff --git a/app/models/invite.rb b/app/models/invite.rb
index 3ad291032..6b84554d2 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -56,6 +56,21 @@ class Invite < ActiveRecord::Base
   end
 
 
+  def add_groups_for_topic(topic)
+    if topic.category
+      (topic.category.groups - groups).each { |group| group.add(user) }
+    end
+  end
+
+  def self.extend_permissions(topic, user, invited_by)
+    if topic.private_message?
+      topic.grant_permission_to_user(user.email)
+    elsif topic.category && topic.category.groups.any?
+      if Guardian.new(invited_by).can_invite_to?(topic)
+        (topic.category.groups - user.groups).each { |group| group.add(user) }
+      end
+    end
+  end
   # Create an invite for a user, supplying an optional topic
   #
   # Return the previously existing invite if already exists. Returns nil if the invite can't be created.
@@ -64,7 +79,7 @@ class Invite < ActiveRecord::Base
     user = User.find_by(email: lower_email)
 
     if user
-      topic.grant_permission_to_user(lower_email) if topic && topic.private_message?
+      extend_permissions(topic, user, invited_by) if topic
       return nil
     end
 
@@ -93,6 +108,11 @@ class Invite < ActiveRecord::Base
       group_ids.each do |group_id|
         invite.invited_groups.create!(group_id: group_id)
       end
+    else
+      if topic && topic.category # && Guardian.new(invited_by).can_invite_to?(topic)
+        group_ids = topic.category.groups.pluck(:id) - invite.invited_groups.pluck(:group_id)
+        group_ids.each { |group_id| invite.invited_groups.create!(group_id: group_id) }
+      end
     end
 
     Jobs.enqueue(:invite_email, invite_id: invite.id)
diff --git a/lib/guardian.rb b/lib/guardian.rb
index d644e5485..d3e2911ee 100644
--- a/lib/guardian.rb
+++ b/lib/guardian.rb
@@ -197,6 +197,12 @@ class Guardian
     is_me?(user)
   end
 
+  def invitations_allowed?
+    !SiteSetting.enable_sso &&
+      SiteSetting.enable_local_logins &&
+      (!SiteSetting.must_approve_users? || is_staff?)
+  end
+
   def can_invite_to_forum?(groups=nil)
     authenticated? &&
     !SiteSetting.enable_sso &&
@@ -209,10 +215,21 @@ class Guardian
   end
 
   def can_invite_to?(object, group_ids=nil)
-    can_invite = can_see?(object) && can_invite_to_forum? && ( group_ids.blank? || is_admin? )
-    #TODO how should invite to PM work?
-    can_invite = can_invite && ( !object.category.read_restricted || is_admin? ) if object.is_a?(Topic) && object.category
-    can_invite
+    return false if ! authenticated?
+    return false if ! invitations_allowed?
+    return true if is_admin?
+    return false if ! can_see?(object)
+
+    return false if group_ids.present?
+
+    if object.is_a?(Topic) && object.category
+      if object.category.groups.any?
+        return true if object.category.groups.all? { |g| can_edit_group?(g) }
+      end
+      return false if object.category.read_restricted
+    end
+
+    user.has_trust_level?(TrustLevel[2])
   end
 
   def can_bulk_invite_to_forum?(user)
diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb
index 4431ccf59..0670605b8 100644
--- a/spec/components/guardian_spec.rb
+++ b/spec/components/guardian_spec.rb
@@ -266,6 +266,9 @@ describe Guardian do
     let(:user) { topic.user }
     let(:moderator) { Fabricate(:moderator) }
     let(:admin) { Fabricate(:admin) }
+    let(:private_category)  { Fabricate(:private_category, group: group) }
+    let(:group_private_topic) { Fabricate(:topic, category: private_category) }
+    let(:group_manager) { group_private_topic.user.tap { |u| group.add(u); group.appoint_manager(u) } }
 
     it 'handles invitation correctly' do
       expect(Guardian.new(nil).can_invite_to?(topic)).to be_falsey
@@ -298,6 +301,9 @@ describe Guardian do
       expect(Guardian.new(admin).can_invite_to?(private_topic)).to be_truthy
     end
 
+    it 'returns true for a group manager' do
+      expect(Guardian.new(group_manager).can_invite_to?(group_private_topic)).to be_truthy
+    end
   end
 
   describe 'can_see?' do
diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb
index 490545cfe..0036c209b 100644
--- a/spec/controllers/topics_controller_spec.rb
+++ b/spec/controllers/topics_controller_spec.rb
@@ -790,6 +790,20 @@ describe TopicsController do
       expect { xhr :post, :invite, topic_id: 1, email: 'jake@adventuretime.ooo' }.to raise_error(Discourse::NotLoggedIn)
     end
 
+    describe 'when logged in as group manager' do
+      let(:group_manager) { log_in }
+      let(:group) { Fabricate(:group).tap { |g| g.add(group_manager); g.appoint_manager(group_manager) } }
+      let(:private_category)  { Fabricate(:private_category, group: group) }
+      let(:group_private_topic) { Fabricate(:topic, category: private_category, user: group_manager) }
+      let(:recipient) { 'jake@adventuretime.ooo' }
+
+      it "should attach group to the invite" do
+        xhr :post, :invite, topic_id: group_private_topic.id, user: recipient
+        expect(response).to be_success
+        expect(Invite.find_by(email: recipient).groups).to eq([group])
+      end
+    end
+
     describe 'when logged in' do
       before do
         @topic = Fabricate(:topic, user: log_in)
@@ -806,7 +820,7 @@ describe TopicsController do
         end
       end
 
-      describe 'with permission' do
+      describe 'with admin permission' do
 
         let!(:admin) do
           log_in :admin
diff --git a/spec/fabricators/category_fabricator.rb b/spec/fabricators/category_fabricator.rb
index 1f237b5d6..5a2336627 100644
--- a/spec/fabricators/category_fabricator.rb
+++ b/spec/fabricators/category_fabricator.rb
@@ -13,3 +13,15 @@ Fabricator(:happy_category, from: :category) do
   slug 'happy'
   user
 end
+
+Fabricator(:private_category, from: :category) do
+  transient :group
+
+  name 'Private Category'
+  slug 'private'
+  user
+  after_build do |cat, transients|
+    cat.update!(read_restricted: true)
+    cat.category_groups.build(group_id: transients[:group].id, permission_type: :full)
+  end
+end
diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb
index a7a1b02a2..943020330 100644
--- a/spec/models/invite_spec.rb
+++ b/spec/models/invite_spec.rb
@@ -127,6 +127,28 @@ describe Invite do
     end
   end
 
+  context 'to a group-private topic' do
+    let(:group) { Fabricate(:group) }
+    let(:private_category)  { Fabricate(:private_category, group: group) }
+    let(:group_private_topic) { Fabricate(:topic, category: private_category) }
+    let(:inviter) { group_private_topic.user }
+
+    before do
+      @invite = group_private_topic.invite_by_email(inviter, iceking)
+    end
+
+    it 'should add the groups to the invite' do
+      expect(@invite.groups).to eq([group])
+    end
+
+    context 'when duplicated' do
+      it 'should not duplicate the groups' do
+        expect(group_private_topic.invite_by_email(inviter, iceking)).to eq(@invite)
+        expect(@invite.groups).to eq([group])
+      end
+    end
+  end
+
   context 'an existing user' do
     let(:topic) { Fabricate(:topic, category_id: nil, archetype: 'private_message') }
     let(:coding_horror) { Fabricate(:coding_horror) }
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index 0f49c4143..66ce8e17b 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -1,4 +1,4 @@
-# encoding: UTF-8
+# encoding: utf-8
 
 require 'spec_helper'
 require_dependency 'post_destroyer'
@@ -1352,4 +1352,37 @@ describe Topic do
     topic.last_posted_at = 1.minute.ago
     expect(topic.save).to eq(true)
   end
+
+  context 'invite by group manager' do
+    let(:group_manager) { Fabricate(:user) }
+    let(:group) { Fabricate(:group).tap { |g| g.add(group_manager); g.appoint_manager(group_manager) } }
+    let(:private_category)  { Fabricate(:private_category, group: group) }
+    let(:group_private_topic) { Fabricate(:topic, category: private_category, user: group_manager) }
+
+    context 'to an email' do
+      let(:randolph) { 'randolph@duke.ooo' }
+
+      it "should attach group to the invite" do
+        invite = group_private_topic.invite(group_manager, randolph)
+        expect(invite.groups).to eq([group])
+      end
+    end
+
+    # should work for an existing user - give access, send notification
+    context 'to an existing user' do
+      let(:walter) { Fabricate(:walter_white) }
+
+      it "should add user to the group" do
+        expect(Guardian.new(walter).can_see?(group_private_topic)).to be_falsey
+        invite = group_private_topic.invite(group_manager, walter.email)
+        expect(invite).to be_nil
+        expect(walter.groups).to include(group)
+        expect(Guardian.new(walter).can_see?(group_private_topic)).to be_truthy
+      end
+    end
+
+    context 'to a previously-invited user' do
+
+    end
+  end
 end