FEATURE: Add request membership button for allowed groups.

This commit is contained in:
Guo Xiang Tan 2016-12-12 22:46:45 +08:00
parent 664feca199
commit da7009a968
17 changed files with 172 additions and 16 deletions

View File

@ -1,5 +1,6 @@
import { popupAjaxError } from 'discourse/lib/ajax-error'; import { popupAjaxError } from 'discourse/lib/ajax-error';
import { propertyEqual } from 'discourse/lib/computed'; import { propertyEqual } from 'discourse/lib/computed';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
adminGroupsType: Ember.inject.controller(), adminGroupsType: Ember.inject.controller(),
@ -35,6 +36,16 @@ export default Ember.Controller.extend({
]; ];
}.property(), }.property(),
@computed('model.visible', 'model.public', 'model.alias_level')
disableMembershipRequestSetting(visible, publicGroup) {
return !visible || publicGroup || !this.get('model.canEveryoneMention');
},
@computed('model.visible', 'model.allow_membership_requests')
disablePublicSetting(visible, allowMembershipRequests) {
return !visible || allowMembershipRequests;
},
actions: { actions: {
next() { next() {
if (this.get("showingLast")) { return; } if (this.get("showingLast")) { return; }

View File

@ -64,16 +64,29 @@
{{#unless model.automatic}} {{#unless model.automatic}}
<div> <div>
<label for="primary_group"> <label>
{{input type="checkbox" checked=model.primary_group}} {{input type="checkbox"
{{i18n 'admin.groups.primary_group'}} checked=model.public
disabled=disablePublicSetting}}
{{i18n 'groups.public'}}
</label> </label>
</div> </div>
<div> <div>
<label> <label>
{{input type="checkbox" checked=model.public}} {{input type="checkbox"
{{i18n 'groups.public'}} checked=model.allow_membership_requests
disabled=disableMembershipRequestSetting}}
{{i18n 'groups.allow_membership_requests'}}
</label>
</div>
<div>
<label for="primary_group">
{{input type="checkbox" checked=model.primary_group}}
{{i18n 'admin.groups.primary_group'}}
</label> </label>
</div> </div>
{{/unless}} {{/unless}}

View File

@ -22,6 +22,11 @@ export default Ember.Controller.extend({
return !!(this.currentUser) && publicGroup; return !!(this.currentUser) && publicGroup;
}, },
@computed('model.allow_membership_requests', 'model.alias_level')
canRequestMembership(allowMembershipRequests, aliasLevel) {
return !!(this.currentUser) && allowMembershipRequests && aliasLevel === 99;
},
actions: { actions: {
removeMember(user) { removeMember(user) {
this.get('model').removeMember(user); this.get('model').removeMember(user);
@ -34,6 +39,13 @@ export default Ember.Controller.extend({
} }
}, },
requestMembership() {
const groupName = this.get('model.name');
const title = I18n.t('groups.request_membership_pm.title');
const body = I18n.t('groups.request_membership_pm.body', { groupName });
this.transitionToRoute(`/new-message?groupname=${groupName}&title=${title}&body=${body}`);
},
joinGroup() { joinGroup() {
this.set('updatingMembership', true); this.set('updatingMembership', true);
const model = this.get('model'); const model = this.get('model');

View File

@ -1,5 +1,5 @@
import { ajax } from 'discourse/lib/ajax'; import { ajax } from 'discourse/lib/ajax';
import computed from "ember-addons/ember-computed-decorators"; import { default as computed, observes } from "ember-addons/ember-computed-decorators";
import GroupHistory from 'discourse/models/group-history'; import GroupHistory from 'discourse/models/group-history';
const Group = Discourse.Model.extend({ const Group = Discourse.Model.extend({
@ -101,6 +101,23 @@ const Group = Discourse.Model.extend({
return this.get('flair_color') ? this.get('flair_color').replace(new RegExp("[^0-9a-fA-F]", "g"), "") : null; return this.get('flair_color') ? this.get('flair_color').replace(new RegExp("[^0-9a-fA-F]", "g"), "") : null;
}, },
@computed('alias_level')
canEveryoneMention(aliasLevel) {
return aliasLevel === '99';
},
@observes("visible", "canEveryoneMention")
_updateAllowMembershipRequests() {
if (!this.get('visible') || !this.get('canEveryoneMention')) {
this.set('allow_membership_requests', false);
}
},
@observes("visible")
_updatePublic() {
if (!this.get('visible')) this.set('public', false);
},
asJSON() { asJSON() {
return { return {
name: this.get('name'), name: this.get('name'),
@ -116,7 +133,8 @@ const Group = Discourse.Model.extend({
flair_bg_color: this.get('flairBackgroundHexColor'), flair_bg_color: this.get('flairBackgroundHexColor'),
flair_color: this.get('flairHexColor'), flair_color: this.get('flairHexColor'),
bio_raw: this.get('bio_raw'), bio_raw: this.get('bio_raw'),
public: this.get('public') public: this.get('public'),
allow_membership_requests: this.get('allow_membership_requests')
}; };
}, },

View File

@ -18,6 +18,11 @@
label="groups.join" label="groups.join"
disabled=updatingMembership}} disabled=updatingMembership}}
{{/if}} {{/if}}
{{else if canRequestMembership}}
{{d-button action="requestMembership"
class="group-index-request"
icon="envelope"
label="groups.request"}}
{{/if}} {{/if}}
{{#load-more selector=".group-members tr" action="loadMore"}} {{#load-more selector=".group-members tr" action="loadMore"}}

View File

@ -9,9 +9,22 @@
{{group-flair-inputs model=model}} {{group-flair-inputs model=model}}
<label> <label>
{{input type='checkbox' checked=model.public class="edit-group-public"}} {{input type='checkbox'
checked=model.public
class="edit-group-public"
disabled=model.allow_membership_requests}}
{{i18n 'groups.public'}} {{i18n 'groups.public'}}
</label> </label>
<label>
{{input type='checkbox'
checked=model.allow_membership_requests
class="edit-group-allow-membership-requests"
disabled=model.public}}
{{i18n 'groups.allow_membership_requests'}}
</label>
</form> </form>
{{/d-modal-body}} {{/d-modal-body}}

View File

@ -23,6 +23,10 @@
} }
} }
.group-index-request, .group-index-join, .group-index-leave {
float: right;
}
table.group-logs { table.group-logs {
width: 100%; width: 100%;

View File

@ -145,7 +145,7 @@ class Admin::GroupsController < Admin::AdminController
:name, :alias_level, :visible, :automatic_membership_email_domains, :name, :alias_level, :visible, :automatic_membership_email_domains,
:automatic_membership_retroactive, :title, :primary_group, :automatic_membership_retroactive, :title, :primary_group,
:grant_trust_level, :incoming_email, :flair_url, :flair_bg_color, :grant_trust_level, :incoming_email, :flair_url, :flair_bg_color,
:flair_color, :bio_raw, :public :flair_color, :bio_raw, :public, :allow_membership_requests
) )
end end
end end

View File

@ -237,7 +237,8 @@ class GroupsController < ApplicationController
:flair_color, :flair_color,
:bio_raw, :bio_raw,
:title, :title,
:public :public,
:allow_membership_requests
) )
end end

View File

@ -17,7 +17,8 @@ class BasicGroupSerializer < ApplicationSerializer
:flair_color, :flair_color,
:bio_raw, :bio_raw,
:bio_cooked, :bio_cooked,
:public :public,
:allow_membership_requests
def include_incoming_email? def include_incoming_email?
staff? staff?

View File

@ -397,8 +397,11 @@ en:
edit: edit:
title: 'Edit Group' title: 'Edit Group'
group_title: 'Title' group_title: 'Title'
request_membership_pm:
title: "Membership Request"
body: "I would like to request membership in @%{groupName}."
name_placeholder: "Group name, no spaces, same as username rule" name_placeholder: "Group name, no spaces, same as username rule"
public: "Allow users to join/leave the group freely" public: "Allow users to join/leave the group freely (Requires group to be visible)"
empty: empty:
posts: "There is no post by members of this group." posts: "There is no post by members of this group."
members: "There is no member in this group." members: "There is no member in this group."
@ -409,6 +412,8 @@ en:
add: "Add" add: "Add"
join: "Join Group" join: "Join Group"
leave: "Leave Group" leave: "Leave Group"
request: "Request to Join Group"
allow_membership_requests: "Allow users to send membership requests to group owners (Requires everyone to be able to mention the group)"
name: "Name" name: "Name"
bio: "About Group" bio: "About Group"
selector_placeholder: "Add members" selector_placeholder: "Add members"

View File

@ -0,0 +1,5 @@
class AddAllowMembershipRequestsToGroups < ActiveRecord::Migration
def change
add_column :groups, :allow_membership_requests, :boolean, default: false, null: false
end
end

View File

@ -40,7 +40,8 @@ describe Admin::GroupsController do
"flair_color"=>nil, "flair_color"=>nil,
"bio_raw"=>nil, "bio_raw"=>nil,
"bio_cooked"=>nil, "bio_cooked"=>nil,
"public"=>false "public"=>false,
"allow_membership_requests"=>false
}]) }])
end end

View File

@ -55,9 +55,10 @@ describe "Groups" do
flair_url: 'fa-adjust', flair_url: 'fa-adjust',
bio_raw: 'testing', bio_raw: 'testing',
title: 'awesome team', title: 'awesome team',
public: true public: true,
allow_membership_requests: true
} } } }
end.to change { GroupHistory.count }.by(6) end.to change { GroupHistory.count }.by(7)
expect(response).to be_success expect(response).to be_success
@ -69,7 +70,8 @@ describe "Groups" do
expect(group.bio_raw).to eq('testing') expect(group.bio_raw).to eq('testing')
expect(group.title).to eq('awesome team') expect(group.title).to eq('awesome team')
expect(group.public).to eq(true) expect(group.public).to eq(true)
expect(GroupHistory.last.subject).to eq('public') expect(group.allow_membership_requests).to eq(true)
expect(GroupHistory.last.subject).to eq('allow_membership_requests')
end end
end end

View File

@ -53,5 +53,19 @@ test("Admin Browsing Groups", () => {
ok(find('.edit-group-bio').length === 1, 'it should display group bio input'); ok(find('.edit-group-bio').length === 1, 'it should display group bio input');
ok(find('.edit-group-title').length === 1, 'it should display group title input'); ok(find('.edit-group-title').length === 1, 'it should display group title input');
ok(find('.edit-group-public').length === 1, 'it should display group public input'); ok(find('.edit-group-public').length === 1, 'it should display group public input');
ok(find('.edit-group-allow-membership-requests').length === 1, 'it should display group allow_membership_requets input');
});
click('.edit-group-public');
andThen(() => {
ok(find('.edit-group-allow-membership-requests[disabled]').length === 1, 'it should disable group allow_membership_requets input');
});
click('.edit-group-public');
click('.edit-group-allow-membership-requests');
andThen(() => {
ok(find('.edit-group-public[disabled]').length === 1, 'it should disable group public input');
}); });
}); });

View File

@ -0,0 +1,33 @@
moduleFor("controller:admin-group");
test("disablePublicSetting", function() {
this.subject().setProperties({
model: { visible: false, allow_membership_requests: false }
});
equal(this.subject().get("disablePublicSetting"), true, "it should disable setting");
this.subject().set("model.visible", true);
equal(this.subject().get("disablePublicSetting"), false, "it should enable setting");
this.subject().set("model.allow_membership_requests", true);
equal(this.subject().get("disablePublicSetting"), true, "it should disable setting");
});
test("disableMembershipRequestSetting", function() {
this.subject().setProperties({
model: { visible: false, public: false, canEveryoneMention: true }
});
equal(this.subject().get("disableMembershipRequestSetting"), true, "it should disable setting");
this.subject().set("model.visible", true);
equal(this.subject().get("disableMembershipRequestSetting"), false, "it should enable setting");
this.subject().set("model.public", true);
equal(this.subject().get("disableMembershipRequestSetting"), true, "it should disalbe setting");
});

View File

@ -19,3 +19,21 @@ test("canJoinGroup", function() {
equal(this.subject().get("canJoinGroup"), false, "can't join group when not logged in"); equal(this.subject().get("canJoinGroup"), false, "can't join group when not logged in");
}); });
test('canRequestMembership', function() {
this.subject().setProperties({
model: { allow_membership_requests: false, alias_level: 0 }
})
equal(this.subject().get('canRequestMembership'), false);
this.subject().setProperties({
currentUser: currentUser(), model: { allow_membership_requests: true, alias_level: 99 }
});
equal(this.subject().get('canRequestMembership'), true);
this.subject().set("model.alias_level", 0);
equal(this.subject().get('canRequestMembership'), false);
});