FEATURE: allows to remove invitees from the modal listing them

This commit is contained in:
jjaffeux 2020-08-09 13:41:10 +02:00
parent 4e5fad6b4f
commit 5c5ffdaaab
9 changed files with 148 additions and 47 deletions

View File

@ -3,7 +3,7 @@
module DiscoursePostEvent
class InviteesController < DiscoursePostEventController
def index
event = Event.find(params['event-id'])
event = Event.find(params[:post_id])
event_invitees = event.invitees
@ -22,28 +22,37 @@ module DiscoursePostEvent
end
def update
invitee = Invitee.find(params[:id])
invitee = Invitee.find_by(id: params[:id], post_id: params[:post_id])
guardian.ensure_can_act_on_invitee!(invitee)
invitee.update_attendance!(invitee_params[:status])
render json: InviteeSerializer.new(invitee)
end
def create
event = Event.find(invitee_params[:post_id])
event = Event.find(params[:post_id])
guardian.ensure_can_see!(event.post)
invitee = Invitee.create_attendance!(
current_user.id,
invitee_params[:post_id],
params[:post_id],
invitee_params[:status]
)
render json: InviteeSerializer.new(invitee)
end
def destroy
event = Event.find_by(id: params[:post_id])
invitee = event.invitees.find_by(id: params[:id])
guardian.ensure_can_act_on_discourse_post_event!(event)
invitee.destroy!
event.publish_update!
render json: success_json
end
private
def invitee_params
params.require(:invitee).permit(:status, :post_id)
params.require(:invitee).permit(:status)
end
end
end

View File

@ -2,7 +2,7 @@
module DiscoursePostEvent
class InviteeSerializer < ApplicationSerializer
attributes :id, :status, :user
attributes :id, :status, :user, :post_id
def status
object.status ? Invitee.statuses[object.status] : nil

View File

@ -1,11 +1,65 @@
import { Result } from "discourse/adapters/rest";
import { ajax } from "discourse/lib/ajax";
import DiscoursePostEventAdapter from "./discourse-post-event-adapter";
import { underscore } from "@ember/string";
export default DiscoursePostEventAdapter.extend({
// TODO: destroy/update/create should be improved in core to allow for nested models
destroyRecord(store, type, record) {
return ajax(
this.pathFor(store, type, {
post_id: record.post_id,
invitee_id: record.id
}),
{
type: "DELETE"
}
);
},
update(store, type, id, attrs) {
const data = {};
const typeField = underscore(this.apiNameFor(type));
data[typeField] = attrs;
return ajax(
this.pathFor(store, type, { invitee_id: id, post_id: attrs.post_id }),
this.getPayload("PUT", data)
).then(function(json) {
return new Result(json[typeField], json);
});
},
createRecord(store, type, attrs) {
const data = {};
const typeField = underscore(this.apiNameFor(type));
data[typeField] = attrs;
return ajax(
this.pathFor(store, type, attrs),
this.getPayload("POST", data)
).then(function(json) {
return new Result(json[typeField], json);
});
},
pathFor(store, type, findArgs) {
const post_id = findArgs["post_id"];
delete findArgs["post_id"];
const invitee_id = findArgs["invitee_id"];
delete findArgs["invitee_id"];
let path =
this.basePath(store, type, findArgs) +
underscore(store.pluralize(this.apiNameFor(type)));
this.basePath(store, type, {}) +
"events/" +
post_id +
"/" +
underscore(store.pluralize(this.apiNameFor()));
if (invitee_id) {
path += `/${invitee_id}`;
}
return this.appendQueryParams(path, findArgs);
},

View File

@ -17,13 +17,20 @@ export default Controller.extend(ModalFunctionality, {
debounce(this, this._fetchInvitees, filter, 250);
},
@action
removeInvitee(invitee) {
invitee
.destroyRecord({ parent: this.model })
.then(() => this._fetchInvitees());
},
_fetchInvitees(filter) {
this.set("isLoading", true);
this.store
.findAll("discourse-post-event-invitee", {
"event-id": this.model.id,
filter
filter,
post_id: this.model.id
})
.then(invitees => this.set("invitees", invitees))
.finally(() => this.set("isLoading", false));

View File

@ -11,6 +11,7 @@
{{#each invitees as |invitee|}}
<li class="invitee">
{{render-invitee invitee}}
{{#if invitee.status}}
<span class="status {{invitee.status}}">
{{i18n (concat "discourse_post_event.models.invitee.status." invitee.status)}}
@ -20,6 +21,14 @@
-
</span>
{{/if}}
{{#if model.can_act_on_discourse_post_event}}
{{d-button
class="btn-danger"
icon="times"
action=(action "removeInvitee" invitee)
}}
{{/if}}
</li>
{{/each}}
</ul>

View File

@ -6,8 +6,7 @@ export default createWidget("discourse-post-event-invitees", {
transform(attrs) {
return {
isPrivateEvent: attrs.eventModel.status === "private",
showAll: attrs.eventModel.stats.invited > 10
isPrivateEvent: attrs.eventModel.status === "private"
};
},
@ -22,17 +21,15 @@ export default createWidget("discourse-post-event-invitees", {
{{/if}}
</div>
{{#if transformed.showAll}}
{{attach
widget="button"
attrs=(hash
className="show-all btn-small"
label="discourse_post_event.event_ui.show_all"
action="showAllInvitees"
actionParam=(hash postId=attrs.eventModel.id)
)
}}
{{/if}}
{{attach
widget="button"
attrs=(hash
className="show-all btn-small"
label="discourse_post_event.event_ui.show_all"
action="showAllInvitees"
actionParam=(hash postId=attrs.eventModel.id)
)
}}
</div>
<ul class="event-invitees-avatars">
{{#each attrs.eventModel.sample_invitees as |invitee|}}

View File

@ -93,7 +93,7 @@ export default createWidget("discourse-post-event", {
this.store.update(
"discourse-post-event-invitee",
this.state.eventModel.watching_invitee.id,
{ status }
{ status, post_id: this.state.eventModel.id }
);
} else {
this.store

View File

@ -112,9 +112,10 @@ after_initialize do
post '/discourse-post-event/events/:id/csv-bulk-invite' => 'events#csv_bulk_invite'
post '/discourse-post-event/events/:id/bulk-invite' => 'events#bulk_invite', format: :json
post '/discourse-post-event/events/:id/invite' => 'events#invite'
put '/discourse-post-event/invitees/:id' => 'invitees#update'
post '/discourse-post-event/invitees' => 'invitees#create'
get '/discourse-post-event/invitees' => 'invitees#index'
put '/discourse-post-event/events/:post_id/invitees/:id' => 'invitees#update'
post '/discourse-post-event/events/:post_id/invitees' => 'invitees#create'
get '/discourse-post-event/events/:post_id/invitees' => 'invitees#index'
delete '/discourse-post-event/events/:post_id/invitees/:id' => 'invitees#destroy'
get '/upcoming-events' => 'upcoming_events#index'
end

View File

@ -28,21 +28,49 @@ module DiscoursePostEvent
pe
}
it 'updates its status' do
invitee = post_event_2.invitees.first
context "updating invitee" do
it 'updates its status' do
invitee = post_event_2.invitees.first
expect(invitee.status).to eq(0)
expect(invitee.status).to eq(0)
put "/discourse-post-event/invitees/#{invitee.id}.json", params: {
invitee: {
status: 'interested'
put "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json", params: {
invitee: {
status: 'interested'
}
}
}
invitee.reload
invitee.reload
expect(invitee.status).to eq(1)
expect(invitee.post_id).to eq(post_1.id)
expect(invitee.status).to eq(1)
expect(invitee.post_id).to eq(post_1.id)
end
end
context 'destroying invitee' do
context 'acting user can act on discourse event' do
it 'destroys the invitee' do
invitee = post_event_2.invitees.first
delete "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json"
expect(Invitee.where(id: invitee.id).length).to eq(0)
expect(response.status).to eq(200)
end
end
context 'acting user cant act on discourse event' do
let(:lurker) { Fabricate(:user) }
before do
sign_in(lurker)
end
it 'doesnt destroy the invitee' do
invitee = post_event_2.invitees.first
delete "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json"
expect(Invitee.where(id: invitee.id).length).to eq(1)
expect(response.status).to eq(403)
end
end
end
context 'when changing status' do
@ -51,7 +79,7 @@ module DiscoursePostEvent
expect(invitee.status).to eq(0)
put "/discourse-post-event/invitees/#{invitee.id}.json", params: {
put "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json", params: {
invitee: {
status: 'interested'
}
@ -60,7 +88,7 @@ module DiscoursePostEvent
tu = TopicUser.get(invitee.event.post.topic, invitee.user)
expect(tu.notification_level).to eq(TopicUser.notification_levels[:tracking])
put "/discourse-post-event/invitees/#{invitee.id}.json", params: {
put "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json", params: {
invitee: {
status: 'going'
}
@ -69,7 +97,7 @@ module DiscoursePostEvent
tu = TopicUser.get(invitee.event.post.topic, invitee.user)
expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
put "/discourse-post-event/invitees/#{invitee.id}.json", params: {
put "/discourse-post-event/events/#{post_event_2.id}/invitees/#{invitee.id}.json", params: {
invitee: {
status: 'not_going'
}
@ -85,26 +113,23 @@ module DiscoursePostEvent
let(:post_event_2) { Fabricate(:event, post: post_1) }
it 'creates an invitee' do
post "/discourse-post-event/invitees.json", params: {
post "/discourse-post-event/events/#{post_event_2.id}/invitees.json", params: {
invitee: {
user_id: user.id,
post_id: post_event_2.id,
status: 'not_going',
}
}
expect(Invitee).to exist(
post_id: post_event_2.id,
user_id: user.id,
status: 2,
)
end
it 'sets tracking of the topic' do
post "/discourse-post-event/invitees.json", params: {
post "/discourse-post-event/events/#{post_event_2.id}/invitees.json", params: {
invitee: {
user_id: user.id,
post_id: post_event_2.id,
status: 'going',
}
}
@ -121,9 +146,8 @@ module DiscoursePostEvent
it 'creates an invitee' do
expect(post_event_2.invitees.length).to eq(0)
post "/discourse-post-event/invitees.json", params: {
post "/discourse-post-event/events/#{post_event_2.id}/invitees.json", params: {
invitee: {
post_id: post_1.id,
status: 'interested'
}
}