Merge pull request #5033 from tgxworld/reason_when_requesting_to_join_a_group
FEATURE: Force user to enter reason when requesting for group members…
This commit is contained in:
commit
898c6ba037
|
@ -91,6 +91,17 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if model.allow_membership_requests}}
|
||||||
|
<div>
|
||||||
|
<label for="membership-request-template">
|
||||||
|
{{i18n 'groups.membership_request_template'}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{expanding-text-area name="membership-request-template"
|
||||||
|
value=model.membership_request_template}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="primary_group">
|
<label for="primary_group">
|
||||||
{{input type="checkbox" checked=model.primary_group}}
|
{{input type="checkbox" checked=model.primary_group}}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
import { default as computed } from 'ember-addons/ember-computed-decorators';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import DiscourseURL from 'discourse/lib/url';
|
import showModal from 'discourse/lib/show-modal';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
loading: false,
|
|
||||||
|
|
||||||
@computed("model.public_admission", "userIsGroupUser")
|
@computed("model.public_admission", "userIsGroupUser")
|
||||||
canJoinGroup(publicAdmission, userIsGroupUser) {
|
canJoinGroup(publicAdmission, userIsGroupUser) {
|
||||||
return publicAdmission && !userIsGroupUser;
|
return publicAdmission && !userIsGroupUser;
|
||||||
|
@ -56,15 +54,9 @@ export default Ember.Component.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
requestMembership() {
|
showRequestMembershipForm() {
|
||||||
if (this.currentUser) {
|
if (this.currentUser) {
|
||||||
this.set('loading', true);
|
showModal("request-group-membership-form", { model: this.get('model') });
|
||||||
|
|
||||||
this.get('model').requestMembership().then(result => {
|
|
||||||
DiscourseURL.routeTo(result.relative_url);
|
|
||||||
}).catch(popupAjaxError).finally(() => {
|
|
||||||
this.set('loading', false);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this._showLoginModal();
|
this._showLoginModal();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
import DiscourseURL from 'discourse/lib/url';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
loading: false,
|
||||||
|
reason: Ember.computed.alias('model.membership_request_template'),
|
||||||
|
|
||||||
|
@computed('model.name')
|
||||||
|
title(groupName) {
|
||||||
|
return I18n.t('groups.membership_request.title', { group_name: groupName });
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed('loading', 'reason')
|
||||||
|
disableSubmit(loading, reason) {
|
||||||
|
return (loading || Ember.isEmpty(reason));
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
requestMember() {
|
||||||
|
if (this.currentUser) {
|
||||||
|
this.set('loading', true);
|
||||||
|
|
||||||
|
this.get('model').requestMembership(this.get('reason')).then(result => {
|
||||||
|
DiscourseURL.routeTo(result.relative_url);
|
||||||
|
}).catch(popupAjaxError).finally(() => {
|
||||||
|
this.set('loading', false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._showLoginModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -147,7 +147,8 @@ const Group = RestModel.extend({
|
||||||
public_exit: this.get('public_exit'),
|
public_exit: this.get('public_exit'),
|
||||||
allow_membership_requests: this.get('allow_membership_requests'),
|
allow_membership_requests: this.get('allow_membership_requests'),
|
||||||
full_name: this.get('full_name'),
|
full_name: this.get('full_name'),
|
||||||
default_notification_level: this.get('default_notification_level')
|
default_notification_level: this.get('default_notification_level'),
|
||||||
|
membership_request_template: this.get('membership_request_template')
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.get('id')) {
|
if (!this.get('id')) {
|
||||||
|
@ -220,9 +221,10 @@ const Group = RestModel.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
requestMembership() {
|
requestMembership(reason) {
|
||||||
return ajax(`/groups/${this.get('name')}/request_membership`, {
|
return ajax(`/groups/${this.get('name')}/request_membership`, {
|
||||||
type: "POST"
|
type: "POST",
|
||||||
|
data: { reason: reason }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,15 +20,11 @@
|
||||||
disabled=true}}
|
disabled=true}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{d-button action="requestMembership"
|
{{d-button action="showRequestMembershipForm"
|
||||||
class="group-index-request"
|
class="group-index-request"
|
||||||
disabled=loading
|
disabled=loading
|
||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
label="groups.request"}}
|
label="groups.request"}}
|
||||||
|
|
||||||
{{#if loading}}
|
|
||||||
{{loading-spinner size="small"}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{yield}}
|
{{yield}}
|
||||||
|
|
|
@ -51,6 +51,18 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if model.allow_membership_requests}}
|
||||||
|
<div>
|
||||||
|
<label for="membership-request-template">
|
||||||
|
{{i18n 'groups.membership_request_template'}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{expanding-text-area name="membership-request-template"
|
||||||
|
value=model.membership_request_template
|
||||||
|
class="group-edit-membership-request-template"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{plugin-outlet name="group-edit" args=(hash group=model)}}
|
{{plugin-outlet name="group-edit" args=(hash group=model)}}
|
||||||
|
|
||||||
{{d-button action="save" class="btn-primary" disabled=saving label="save"}}
|
{{d-button action="save" class="btn-primary" disabled=saving label="save"}}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<form class='request-group-membership-form'>
|
||||||
|
{{#d-modal-body rawTitle=title}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>
|
||||||
|
{{i18n "groups.membership_request.reason"}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{expanding-text-area value=reason}}
|
||||||
|
</div>
|
||||||
|
{{/d-modal-body}}
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{d-button class="btn-primary"
|
||||||
|
disabled=disableSubmit
|
||||||
|
label="groups.membership_request.submit"
|
||||||
|
action="requestMember"}}
|
||||||
|
|
||||||
|
<a {{action "closeModal"}}>{{i18n 'cancel'}}</a>
|
||||||
|
{{conditional-loading-spinner size="small" condition=loading}}
|
||||||
|
</div>
|
||||||
|
</form>
|
|
@ -0,0 +1,5 @@
|
||||||
|
.request-group-membership-form {
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
|
@ -97,6 +97,7 @@ class Admin::GroupsController < Admin::AdminController
|
||||||
|
|
||||||
if group_params[:allow_membership_requests]
|
if group_params[:allow_membership_requests]
|
||||||
group.allow_membership_requests = group_params[:allow_membership_requests]
|
group.allow_membership_requests = group_params[:allow_membership_requests]
|
||||||
|
group.membership_request_template = group_params[:membership_request_template]
|
||||||
end
|
end
|
||||||
|
|
||||||
if group_params[:owner_usernames].present?
|
if group_params[:owner_usernames].present?
|
||||||
|
@ -208,7 +209,8 @@ class Admin::GroupsController < Admin::AdminController
|
||||||
:full_name,
|
:full_name,
|
||||||
:default_notification_level,
|
:default_notification_level,
|
||||||
:usernames,
|
:usernames,
|
||||||
:owner_usernames
|
:owner_usernames,
|
||||||
|
:membership_request_template
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -243,6 +243,8 @@ class GroupsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def request_membership
|
def request_membership
|
||||||
|
params.require(:reason)
|
||||||
|
|
||||||
unless current_user.staff?
|
unless current_user.staff?
|
||||||
RateLimiter.new(current_user, "request_group_membership", 1, 1.day).performed!
|
RateLimiter.new(current_user, "request_group_membership", 1, 1.day).performed!
|
||||||
end
|
end
|
||||||
|
@ -259,7 +261,7 @@ class GroupsController < ApplicationController
|
||||||
|
|
||||||
post = PostCreator.new(current_user,
|
post = PostCreator.new(current_user,
|
||||||
title: I18n.t('groups.request_membership_pm.title', group_name: group_name),
|
title: I18n.t('groups.request_membership_pm.title', group_name: group_name),
|
||||||
raw: I18n.t('groups.request_membership_pm.body', group_name: group_name),
|
raw: params[:reason],
|
||||||
archetype: Archetype.private_message,
|
archetype: Archetype.private_message,
|
||||||
target_usernames: usernames.join(','),
|
target_usernames: usernames.join(','),
|
||||||
skip_validations: true
|
skip_validations: true
|
||||||
|
|
|
@ -22,7 +22,8 @@ class BasicGroupSerializer < ApplicationSerializer
|
||||||
:public_exit,
|
:public_exit,
|
||||||
:allow_membership_requests,
|
:allow_membership_requests,
|
||||||
:full_name,
|
:full_name,
|
||||||
:default_notification_level
|
:default_notification_level,
|
||||||
|
:membership_request_template
|
||||||
|
|
||||||
def include_display_name?
|
def include_display_name?
|
||||||
object.automatic
|
object.automatic
|
||||||
|
|
|
@ -427,6 +427,12 @@ en:
|
||||||
closed_group: Closed Group
|
closed_group: Closed Group
|
||||||
is_group_user: "You are a member of this group"
|
is_group_user: "You are a member of this group"
|
||||||
allow_membership_requests: "Allow users to send membership requests to group owners"
|
allow_membership_requests: "Allow users to send membership requests to group owners"
|
||||||
|
membership_request_template: "Custom template to display to users when sending a membership request"
|
||||||
|
membership_request:
|
||||||
|
submit: "Submit Request"
|
||||||
|
title: "Request to join @%{group_name}"
|
||||||
|
reason: "Let the group owners know why you belong in this group"
|
||||||
|
|
||||||
membership: "Membership"
|
membership: "Membership"
|
||||||
name: "Name"
|
name: "Name"
|
||||||
user_count: "Number of Members"
|
user_count: "Number of Members"
|
||||||
|
|
|
@ -280,7 +280,6 @@ en:
|
||||||
trust_level_4: "trust_level_4"
|
trust_level_4: "trust_level_4"
|
||||||
request_membership_pm:
|
request_membership_pm:
|
||||||
title: "Membership Request for @%{group_name}"
|
title: "Membership Request for @%{group_name}"
|
||||||
body: "I would like to apply for membership in @%{group_name}."
|
|
||||||
|
|
||||||
education:
|
education:
|
||||||
until_posts:
|
until_posts:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddMembershipRequestTemplateToGroups < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :groups, :membership_request_template, :text
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,7 +15,8 @@ RSpec.describe "Managing groups as an admin" do
|
||||||
name: 'testing',
|
name: 'testing',
|
||||||
usernames: [admin.username, user.username].join(","),
|
usernames: [admin.username, user.username].join(","),
|
||||||
owner_usernames: [user.username].join(","),
|
owner_usernames: [user.username].join(","),
|
||||||
allow_membership_requests: true
|
allow_membership_requests: true,
|
||||||
|
membership_request_template: 'Testing',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
|
@ -25,6 +26,7 @@ RSpec.describe "Managing groups as an admin" do
|
||||||
expect(group.name).to eq('testing')
|
expect(group.name).to eq('testing')
|
||||||
expect(group.users).to contain_exactly(admin, user)
|
expect(group.users).to contain_exactly(admin, user)
|
||||||
expect(group.allow_membership_requests).to eq(true)
|
expect(group.allow_membership_requests).to eq(true)
|
||||||
|
expect(group.membership_request_template).to eq('Testing')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -564,6 +564,14 @@ describe "Groups" do
|
||||||
end.to raise_error(Discourse::NotLoggedIn)
|
end.to raise_error(Discourse::NotLoggedIn)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'requires a reason' do
|
||||||
|
sign_in(user)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
xhr :post, "/groups/#{group.name}/request_membership"
|
||||||
|
end.to raise_error(ActionController::ParameterMissing)
|
||||||
|
end
|
||||||
|
|
||||||
it 'should create the right PM' do
|
it 'should create the right PM' do
|
||||||
owner1 = Fabricate(:user, last_seen_at: Time.zone.now)
|
owner1 = Fabricate(:user, last_seen_at: Time.zone.now)
|
||||||
owner2 = Fabricate(:user, last_seen_at: Time.zone.now - 1 .day)
|
owner2 = Fabricate(:user, last_seen_at: Time.zone.now - 1 .day)
|
||||||
|
@ -571,7 +579,8 @@ describe "Groups" do
|
||||||
|
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
|
||||||
xhr :post, "/groups/#{group.name}/request_membership"
|
xhr :post, "/groups/#{group.name}/request_membership",
|
||||||
|
reason: 'Please add me in'
|
||||||
|
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
|
|
||||||
|
@ -586,10 +595,7 @@ describe "Groups" do
|
||||||
group_name: group.name
|
group_name: group.name
|
||||||
))
|
))
|
||||||
|
|
||||||
expect(post.raw).to eq(I18n.t(
|
expect(post.raw).to eq('Please add me in')
|
||||||
'groups.request_membership_pm.body', group_name: group.name
|
|
||||||
))
|
|
||||||
|
|
||||||
expect(topic.archetype).to eq(Archetype.private_message)
|
expect(topic.archetype).to eq(Archetype.private_message)
|
||||||
expect(topic.allowed_users).to contain_exactly(user, owner1, owner2)
|
expect(topic.allowed_users).to contain_exactly(user, owner1, owner2)
|
||||||
expect(topic.allowed_groups).to eq([])
|
expect(topic.allowed_groups).to eq([])
|
||||||
|
|
|
@ -27,9 +27,7 @@ QUnit.test("Editing group", assert => {
|
||||||
assert.ok(find('.group-members-input .item').length === 7, 'it should display group members');
|
assert.ok(find('.group-members-input .item').length === 7, 'it should display group members');
|
||||||
assert.ok(find('.group-members-input-selector').length === 1, 'it should display input to add group members');
|
assert.ok(find('.group-members-input-selector').length === 1, 'it should display input to add group members');
|
||||||
assert.ok(find('.group-members-input-selector .add[disabled]').length === 1, 'add members button should be disabled');
|
assert.ok(find('.group-members-input-selector .add[disabled]').length === 1, 'add members button should be disabled');
|
||||||
});
|
|
||||||
|
|
||||||
andThen(() => {
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
find('.group-edit-allow-membership-requests[disabled]').length === 1,
|
find('.group-edit-allow-membership-requests[disabled]').length === 1,
|
||||||
'it should disable group allow_membership_request input'
|
'it should disable group allow_membership_request input'
|
||||||
|
@ -44,6 +42,11 @@ QUnit.test("Editing group", assert => {
|
||||||
find('.group-edit-public-admission[disabled]').length === 1,
|
find('.group-edit-public-admission[disabled]').length === 1,
|
||||||
'it should disable group public admission input'
|
'it should disable group public admission input'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
find('.group-edit-membership-request-template').length, 1,
|
||||||
|
'it should display the membership request template field'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,34 @@ QUnit.test("User Viewing Group", assert => {
|
||||||
logIn();
|
logIn();
|
||||||
Discourse.reset();
|
Discourse.reset();
|
||||||
|
|
||||||
|
visit("/groups");
|
||||||
|
click('.group-index-request');
|
||||||
|
|
||||||
|
server.post('/groups/Macdonald/request_membership', () => { // eslint-disable-line no-undef
|
||||||
|
return [
|
||||||
|
200,
|
||||||
|
{ "Content-Type": "application/json" },
|
||||||
|
{ relative_url: '/t/internationalization-localization/280' }
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
assert.equal(find('.modal-header').text().trim(), I18n.t(
|
||||||
|
'groups.membership_request.title', { group_name: 'Macdonald' }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.equal(find('.request-group-membership-form textarea').val(), 'Please add me');
|
||||||
|
});
|
||||||
|
|
||||||
|
click('.modal-footer .btn-primary');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
assert.equal(
|
||||||
|
find('.fancy-title').text().trim(),
|
||||||
|
"Internationalization / localization"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
visit("/groups/discourse");
|
visit("/groups/discourse");
|
||||||
|
|
||||||
click('.group-message-button');
|
click('.group-message-button');
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export default {
|
export default {
|
||||||
"/groups.json": {"groups":[{"id":41,"automatic":false,"name":"discourse","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":"","bio_cooked":null,"public_admission":true,"allow_membership_requests":false,"full_name":"Awesome Team"},{"id":42,"automatic":false,"name":"Macdonald","user_count":0,"alias_level":99,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public_admission":false,"allow_membership_requests":true,"full_name":null}],"extras":{"group_user_ids":[]},"total_rows_groups":2,"load_more_groups":"/groups?page=1"}
|
"/groups.json": {"groups":[{"id":41,"automatic":false,"name":"discourse","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":"","bio_cooked":null,"public_admission":true,"allow_membership_requests":false,"full_name":"Awesome Team"},{"id":42,"automatic":false,"name":"Macdonald","user_count":0,"alias_level":99,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public_admission":false,"allow_membership_requests":true,"membership_request_template":"Please add me","full_name":null}],"extras":{"group_user_ids":[]},"total_rows_groups":2,"load_more_groups":"/groups?page=1"}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue