Browse Source

feat: add ability to add speakers with Session

pull/79/head
berkansasmaz 5 years ago
parent
commit
d440ac90e4
No known key found for this signature in database GPG Key ID: 884D815C3F32BE00
  1. 8
      src/EventHub.Application.Contracts/Events/AddSessionDto.cs
  2. 32
      src/EventHub.Application/Events/EventAppService.cs
  3. 2
      src/EventHub.Application/Users/UserAppService.cs
  4. 5
      src/EventHub.Domain/Events/Event.cs
  5. 29
      src/EventHub.Domain/Events/Session.cs
  6. 5
      src/EventHub.Domain/Events/Track.cs
  7. 1
      src/EventHub.HttpApi/Controllers/Users/UserController.cs
  8. 30
      src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml
  9. 3
      src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.css
  10. 107
      src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.js
  11. 5
      src/EventHub.Web/Pages/Events/New.cshtml

8
src/EventHub.Application.Contracts/Events/AddSessionDto.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EventHub.Events;
@ -24,4 +25,11 @@ public class AddSessionDto
public string Description { get; set; }
public string Language { get; set; }
public List<string> SpeakerUserNames { get; set; }
public AddSessionDto()
{
SpeakerUserNames = new List<string>();
}
}

32
src/EventHub.Application/Events/EventAppService.cs

@ -7,6 +7,7 @@ using EventHub.Events.Registrations;
using EventHub.Organizations;
using EventHub.Users;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Authorization;
using Volo.Abp.BlobStoring;
@ -184,6 +185,14 @@ namespace EventHub.Events
dto.OrganizationDisplayName = organization.DisplayName;
var user = await _userRepository.GetAsync(organization.OwnerUserId);
if (@event.IsDraft)
{
if (user.Id != CurrentUser.GetId())
{
throw new AbpAuthorizationException();
}
}
dto.OwnerUserName = user.UserName;
dto.OwnerEmail = user.Email;
@ -302,6 +311,7 @@ namespace EventHub.Events
public async Task AddSessionAsync(Guid id, AddSessionDto input)
{
var @event = await _eventRepository.GetAsync(id);
@event.AddSession(
input.TrackId,
GuidGenerator.Create(),
@ -309,8 +319,10 @@ namespace EventHub.Events
input.StartTime,
input.EndTime,
input.Description,
input.Language
input.Language,
await GetUserIdsByUserNamesAsync(input.SpeakerUserNames)
);
await _eventRepository.UpdateAsync(@event);
}
@ -334,6 +346,24 @@ namespace EventHub.Events
await _eventBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting: true);
}
private async Task<List<Guid>> GetUserIdsByUserNamesAsync(List<string> userNames)
{
var speakerUserIDs = new List<Guid>();
foreach (var userName in userNames.Where(userName => !userName.IsNullOrWhiteSpace()))
{
var user = await _userRepository.FindAsync(x => x.UserName == userName.Trim());
if (user is null)
{
throw new BusinessException(EventHubErrorCodes.UserNotFound)
.WithData("UserName", userName);
}
speakerUserIDs.Add(user.Id);
}
return speakerUserIDs;
}
private async Task CheckOwnerControlAsync(Event @event)
{

2
src/EventHub.Application/Users/UserAppService.cs

@ -29,7 +29,7 @@ namespace EventHub.Users
var userQueryable = await _userRepository.GetQueryableAsync();
var query = userQueryable
.Where(u => u.UserName.Contains(username))
.Where(u => u.UserName.ToLower().Contains(username))
.Select(x => new UserWithoutDetails
{
Id = x.Id,

5
src/EventHub.Domain/Events/Event.cs

@ -179,7 +179,8 @@ namespace EventHub.Events
DateTime startTime,
DateTime endTime,
string description,
string language)
string language,
ICollection<Guid> speakerUserIds)
{
if (startTime > endTime)
{
@ -192,7 +193,7 @@ namespace EventHub.Events
}
var track = GetTrack(trackId);
track.AddSession(sessionId, title, startTime, endTime, description, language);
track.AddSession(sessionId, title, startTime, endTime, description, language, speakerUserIds);
return this;
}

29
src/EventHub.Domain/Events/Session.cs

@ -34,7 +34,8 @@ namespace EventHub.Events
DateTime startTime,
DateTime endTime,
string description,
string language)
string language,
ICollection<Guid> speakerUserIds)
: base(id)
{
TrackId = trackId;
@ -42,7 +43,9 @@ namespace EventHub.Events
SetDescription(description);
SetTime(startTime, endTime);
SetLanguage(language);
Speakers = new Collection<Speaker>();
AddSpeakers(speakerUserIds);
}
public Session SetTitle(string title)
@ -75,5 +78,29 @@ namespace EventHub.Events
return this;
}
internal Session AddSpeakers(ICollection<Guid> userIds)
{
foreach (var userId in userIds)
{
AddSpeaker(userId);
}
return this;
}
internal Session AddSpeaker(Guid userId)
{
Speakers.Add(new Speaker(Id, userId));
return this;
}
internal Session RemoveSpeaker(Guid userId)
{
Speakers.RemoveAll(t => t.UserId == userId);
return this;
}
}
}

5
src/EventHub.Domain/Events/Track.cs

@ -42,7 +42,8 @@ namespace EventHub.Events
DateTime startTime,
DateTime endTime,
string description,
string language)
string language,
ICollection<Guid> speakerUserIds)
{
if (startTime > endTime)
{
@ -58,7 +59,7 @@ namespace EventHub.Events
}
}
Sessions.Add(new Session(sessionId, Id, title, startTime, endTime, description, language));
Sessions.Add(new Session(sessionId, Id, title, startTime, endTime, description, language, speakerUserIds));
return this;
}

1
src/EventHub.HttpApi/Controllers/Users/UserController.cs

@ -32,6 +32,7 @@ namespace EventHub.Controllers.Users
[Route("contains/{username}")]
public async Task<List<UserInListDto>> GetListByUserName(string username)
{
username = username.Trim().ToLower();
return await _userAppService.GetListByUserName(username);
}
}

30
src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml

@ -101,36 +101,28 @@
<input type="hidden" id="TrackId" name="TrackId" value="TrackIdPlaceHolder" />
<div class="modal-body profile-content px-5">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="TitleInSession" name="Title" placeholder=" "
required minLength=@SessionConsts.MinTitleLength maxLength=@SessionConsts.MaxTitleLength>
<label for="TitleInSession">Title</label>
<input type="text" class="form-control" id="TitleInNewSessionModal" name="Title" placeholder=" " required minLength=@SessionConsts.MinTitleLength maxLength=@SessionConsts.MaxTitleLength />
<label for="TitleInNewSessionModal">Title</label>
</div>
<div class="form-floating mb-3">
<textarea type="text" class="form-control" id="DescriptionInSession" name="Description"
placeholder=" " required minLength=@SessionConsts.MinDescriptionLength
maxLength=@SessionConsts.MaxDescriptionLength></textarea>
<label for="DescriptionInSession">Description</label>
<textarea type="text" class="form-control" id="DescriptionInNewSessionModal" name="Description" placeholder=" " required minLength=@SessionConsts.MinDescriptionLength maxLength=@SessionConsts.MaxDescriptionLength></textarea>
<label for="DescriptionInNewSessionModal">Description</label>
</div>
<div class="form-floating mb-3">
<input type="datetime-local" class="form-control" id="StartTimeInSession" name="StartTime"
placeholder=" " required>
<label for="StartTimeInSession">Start Time</label>
<input type="datetime-local" class="form-control" id="StartTimeInNewSessionModal" name="StartTime" placeholder=" " required />
<label for="StartTimeInNewSessionModal">Start Time</label>
</div>
<div class="form-floating mb-3">
<input type="datetime-local" class="form-control" id="EndTimeInSession" name="EndTime"
placeholder=" " required>
<label for="EndTimeInSession">End Time</label>
<input type="datetime-local" class="form-control" id="EndTimeInNewSessionModal" name="EndTime"placeholder=" " required />
<label for="EndTimeInNewSessionModal">End Time</label>
</div>
<div class="form-floating mb-3">
<select id="LanguageInSession" name="Language" asp-items="languages" aria-label="en" class="form-select" required>
<select id="LanguageInNewSessionModal" name="Language" asp-items="languages" aria-label="en" class="form-select" required>
</select>
<label for="LanguageInSession">Language</label>
<label for="LanguageInNewSessionModal">Language</label>
</div>
<div class="form-floating mb-3">
<input type="text" class="form-control" id="SpeakersInSession" placeholder=" " list="suggestions">
<datalist id="suggestions">
</datalist>
<label for="SpeakersInSession">Speakers</label>
<input type="text" class="form-control" id="SpeakersInNewSessionModal" placeholder="Speakers" data-multiple />
</div>
</div>
<div class="modal-footer border-0 p-5 pt-2">

3
src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.css

@ -0,0 +1,3 @@
.awesomplete {
display: inline!important;
}

107
src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.js

@ -8,7 +8,7 @@
"NewTrack": "NewTrack",
"NewSession": "NewSession"
}
var widgetManager = $wrapper.data('abp-widget-manager');
var eventApiService = eventHub.controllers.events.event;
var eventIdInput = $('#EventId');
@ -18,7 +18,7 @@
eventUrlCode: "",
stepType: stepType.NewEvent
}
var getFilters = function () {
return filter;
}
@ -26,7 +26,7 @@
var init = function () {
FocusTrackNameInputInModalEventHandler("AddTrackModal")
FocusTrackNameInputInModalEventHandler("EditTrackModal")
if (eventIdInput.val().length === 36) {
// TODO: Add organization in UppdateEventDto
$('#OrganizationId').prop("disabled", true).removeAttr('name');
@ -87,13 +87,13 @@
});
});
}
function FocusTrackNameInputInModalEventHandler(elementId) {
$('#'+ elementId).on('shown.bs.modal', function () {
$('#' + elementId).on('shown.bs.modal', function () {
$(this).find('input[type=text]').trigger('focus')
});
}
function OpenEditTrackModalClickEventHandler() {
$('.edit-track-button').click(function (e) {
var editTrackModal = $('#EditTrackModal');
@ -114,11 +114,11 @@
var trackId = editTrackForm.find('#TrackId').val();
var oldTrackName = $('#' + trackId).data('track-name');
var trackName = editTrackForm.find('#TrackNameInput').val().trim();
if (trackName === oldTrackName){
if (trackName === oldTrackName) {
abp.notify.error('Track name must be different from the previous name.');
return;
}
eventApiService.updateTrack(eventIdInput.val(), trackId, { name: trackName}).then(function () {
eventApiService.updateTrack(eventIdInput.val(), trackId, {name: trackName}).then(function () {
$('#EditTrackModal').modal('hide');
abp.notify.success('Updated the track');
FillFilter(stepType.NewTrack)
@ -126,7 +126,7 @@
});
});
}
function DeleteTrackButtonClickEventHandler() {
$('.delete-track-button').click(function (e) {
eventApiService.deleteTrack(eventIdInput.val(), this.id).then(function () {
@ -143,31 +143,10 @@
var clickedSessionId = this.id;
var trackId = $('#' + clickedSessionId).data('track-id');
addSessionModal.find('#TrackId').val(trackId);
$('#StartTimeInSession').val($('#inputStartdate').val());
$('#EndTimeInSession').val($('#inputEnddate').val());
function delay(callback, ms) {
var timer = 0;
return function() {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, ms || 0);
};
}
$('#SpeakersInSession').keyup(delay(function (e) {
eventHub.controllers.users.user.getListByUserName($(this).val()).then(function (res) {
$.each(res, function (k,v) {
if ( $("#suggestions option[value='" + v.userName + "']").length === 0){
$("#suggestions").append($('<option>', {
value: v.userName,
}));
}
});
});
}, 500));
$('#StartTimeInNewSessionModal').val($('#inputStartdate').val());
$('#EndTimeInNewSessionModal').val($('#inputEnddate').val());
CreateAutoCompleteByElement("SpeakersInNewSessionModal");
});
}
@ -175,10 +154,15 @@
var addNewSessionForm = $('#AddNewSessionForm');
addNewSessionForm.submit(function (e) {
e.preventDefault();
if (!addNewSessionForm.valid()) {
return false;
}
var userNameList = $('#SpeakersInNewSessionModal').val().split(/[ , ]+/);
userNameList = userNameList.filter(v => v !== '');
var input = $(this).serializeFormToObject();
input.speakerUserNames = userNameList;
eventApiService.addSession(eventIdInput.val(), input).then(function () {
$('#AddSessionModal').modal('hide');
abp.notify.success('Added the session');
@ -198,6 +182,51 @@
});
}
function CreateAutoCompleteByElement(id) {
var element = document.getElementById(id);
var awesomplete = new Awesomplete(element, {
filter: function (text, input) {
return Awesomplete.FILTER_CONTAINS(text, input.match(/[^,]*$/)[0]);
},
item: function (text, input) {
return Awesomplete.ITEM(text, input.match(/[^,]*$/)[0]);
},
replace: function (text) {
var before = this.input.value.match(/^.+,\s*|/)[0];
this.input.value = before + text + " , ";
},
list: []
});
function delay(callback, ms) {
var timer = 0;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, ms || 0);
};
}
$('#' + id).keyup(delay(function (e) {
var filterText = $(this).val().split(/[ ,]+/);
eventHub.controllers.users.user.getListByUserName(filterText[filterText.length-1]).then(function (res) {
var userNames = []
$.each(res, function (i, v) {
if (!$('#' + id).val().includes(v.userName)){
userNames.push(v.userName);
}
});
awesomplete.list = userNames
awesomplete.evaluate();
});
}, 500));
}
function FillFilter(stepType) {
filter.stepType = stepType;
filter.eventUrlCode = eventUrlCodeInput.val();
@ -209,18 +238,18 @@
}, 100);
}
$(document).ajaxSend(function( event, jqxhr, settings, exception ) {
$(document).ajaxSend(function (event, jqxhr, settings, exception) {
ButtonsBusy(true)
});
$(document).ajaxComplete(function( event, jqxhr, settings, exception ) {
$(document).ajaxComplete(function (event, jqxhr, settings, exception) {
ButtonsBusy(false)
});
function ButtonsBusy(isBusy) {
if (isBusy){
if (isBusy) {
$('button[type=submit]').attr('disabled', 'disabled')
}else{
} else {
$('button[type=submit]').removeAttr('disabled')
}
}

5
src/EventHub.Web/Pages/Events/New.cshtml

@ -7,6 +7,11 @@
@section scripts {
<abp-script src="/Pages/Events/New.js"/>
<abp-script src="/libs/awesomplete/awesomplete.min.js" />
}
@section styles {
<abp-style src="/libs/awesomplete/awesomplete.css" />
}
<div class="container mt-5">

Loading…
Cancel
Save