public async Task SetFields(int projectId, int characterId, Dictionary <int, string?> requestFieldValues) { var character = await LoadProjectSubEntityAsync <Character>(projectId, characterId); _ = character.RequestMasterAccess(CurrentUserId, acl => acl.CanEditRoles); _ = character.EnsureProjectActive(); var changedFields = FieldSaveHelper.SaveCharacterFields(CurrentUserId, character, requestFieldValues, FieldDefaultValueGenerator); MarkChanged(character); FieldsChangedEmail?email = null; if (changedFields.Any()) { var user = await UserRepository.GetById(CurrentUserId); email = EmailHelpers.CreateFieldsEmail( character, s => s.FieldChange, user, changedFields); } await UnitOfWork.SaveChangesAsync(); if (email != null) { await EmailService.Email(email); } }
//TODO: move character operations to a separate service. public async Task EditCharacter(int currentUserId, int characterId, int projectId, string name, bool isPublic, IReadOnlyCollection <int> parentCharacterGroupIds, bool isAcceptingClaims, string contents, bool hidePlayerForCharacter, IDictionary <int, string> characterFields, bool isHot) { var character = await LoadProjectSubEntityAsync <Character>(projectId, characterId); character.RequestMasterAccess(currentUserId, acl => acl.CanEditRoles); character.EnsureProjectActive(); var changedAttributes = new Dictionary <string, PreviousAndNewValue>(); changedAttributes.Add("Имя персонажа", new PreviousAndNewValue(name, character.CharacterName.Trim())); character.CharacterName = name.Trim(); character.IsAcceptingClaims = isAcceptingClaims; character.IsPublic = isPublic; var newDescription = new MarkdownString(contents); changedAttributes.Add("Описание персонажа", new PreviousAndNewValue(newDescription, character.Description)); character.Description = newDescription; character.HidePlayerForCharacter = hidePlayerForCharacter; character.IsHot = isHot; character.IsActive = true; character.ParentCharacterGroupIds = await ValidateCharacterGroupList(projectId, Required(parentCharacterGroupIds), ensureNotSpecial : true); var changedFields = FieldSaveHelper.SaveCharacterFields(currentUserId, character, characterFields, FieldDefaultValueGenerator); MarkChanged(character); MarkTreeModified(character.Project); //TODO: Can be smarter FieldsChangedEmail email = null; changedAttributes = changedAttributes .Where(attr => attr.Value.DisplayString != attr.Value.PreviousDisplayString) .ToDictionary(x => x.Key, x => x.Value); if (changedFields.Any() || changedAttributes.Any()) { var user = await UserRepository.GetById(currentUserId); email = EmailHelpers.CreateFieldsEmail( character, s => s.FieldChange, user, changedFields, changedAttributes); } await UnitOfWork.SaveChangesAsync(); if (email != null) { await EmailService.Email(email); } }
public async Task AddClaimFromUser(int projectId, int?characterGroupId, int?characterId, string claimText, IDictionary <int, string> fields) { var source = await ProjectRepository.GetClaimSource(projectId, characterGroupId, characterId); EnsureCanAddClaim(CurrentUserId, source); var responsibleMaster = source.GetResponsibleMasters().FirstOrDefault(); var claim = new Claim() { CharacterGroupId = characterGroupId, CharacterId = characterId, ProjectId = projectId, PlayerUserId = CurrentUserId, PlayerAcceptedDate = Now, CreateDate = Now, ClaimStatus = Claim.Status.AddedByUser, ResponsibleMasterUserId = responsibleMaster?.UserId, ResponsibleMasterUser = responsibleMaster, LastUpdateDateTime = Now, CommentDiscussion = new CommentDiscussion() { CommentDiscussionId = -1, ProjectId = projectId }, }; if (!string.IsNullOrWhiteSpace(claimText)) { claim.CommentDiscussion.Comments.Add(new Comment { CommentDiscussionId = -1, AuthorUserId = CurrentUserId, CommentText = new CommentText { Text = new MarkdownString(claimText) }, CreatedAt = Now, IsCommentByPlayer = true, IsVisibleToPlayer = true, ProjectId = projectId, LastEditTime = Now, }); } UnitOfWork.GetDbSet <Claim>().Add(claim); var updatedFields = FieldSaveHelper.SaveCharacterFields(CurrentUserId, claim, fields, FieldDefaultValueGenerator); var claimEmail = EmailHelpers.CreateClaimEmail <NewClaimEmail>(claim, claimText ?? "", s => s.ClaimStatusChange, CommentExtraAction.NewClaim, await UserRepository.GetById(CurrentUserId)); claimEmail.UpdatedFields = updatedFields; await UnitOfWork.SaveChangesAsync(); await EmailService.Email(claimEmail); }
public async Task AppoveByMaster(int projectId, int claimId, string commentText) { var claim = await LoadClaimForApprovalDecline(projectId, claimId, CurrentUserId); if (claim.ClaimStatus == Claim.Status.CheckedIn) { throw new ClaimWrongStatusException(claim); } claim.MasterAcceptedDate = Now; claim.ChangeStatusWithCheck(Claim.Status.Approved); claim.ResponsibleMasterUserId = claim.ResponsibleMasterUserId ?? CurrentUserId; AddCommentImpl(claim, null, commentText, true, CommentExtraAction.ApproveByMaster); if (!claim.Project.Details.EnableManyCharacters) { foreach (var otherClaim in claim.OtherPendingClaimsForThisPlayer()) { otherClaim.EnsureCanChangeStatus(Claim.Status.DeclinedByMaster); otherClaim.MasterDeclinedDate = Now; otherClaim.ClaimStatus = Claim.Status.DeclinedByMaster; await EmailService.Email( await AddCommentWithEmail <DeclineByMasterEmail>("Заявка автоматически отклонена, т.к. другая заявка того же игрока была принята в тот же проект", otherClaim, true, s => s.ClaimStatusChange, null, CommentExtraAction.DeclineByMaster)); } } if (claim.Group != null) { //TODO: Добавить здесь возможность ввести имя персонажа или брать его из заявки ConvertToIndividual(claim); } MarkCharacterChangedIfApproved(claim); Debug.Assert(claim.Character != null, "claim.Character != null"); claim.Character.ApprovedClaimId = claim.ClaimId; //We need to resave fields here, because it may cause some field values to move from Claim to Characters //which also could trigger changing of special groups // ReSharper disable once MustUseReturnValue we don't need send email here FieldSaveHelper.SaveCharacterFields(CurrentUserId, claim, new Dictionary <int, string>(), FieldDefaultValueGenerator); await UnitOfWork.SaveChangesAsync(); await EmailService.Email( EmailHelpers.CreateClaimEmail <ApproveByMasterEmail>(claim, commentText, s => s.ClaimStatusChange, CommentExtraAction.ApproveByMaster, await UserRepository.GetById(CurrentUserId))); }
public async Task CheckInClaim(int projectId, int claimId, int money) { var claim = (await ClaimsRepository.GetClaim(projectId, claimId)).RequestAccess(CurrentUserId); //TODO Specific right claim.EnsureCanChangeStatus(Claim.Status.CheckedIn); var validator = new ClaimCheckInValidator(claim); if (!validator.CanCheckInInPrinciple) { throw new ClaimWrongStatusException(claim); } FinanceOperationEmail financeEmail = null; if (money > 0) { var paymentType = claim.Project.ProjectAcls.Single(acl => acl.UserId == CurrentUserId) .GetCashPaymentType(); financeEmail = await AcceptFeeImpl(".", Now, 0, money, paymentType, claim); } else if (money < 0) { throw new InvalidOperationException(); } if (!validator.CanCheckInNow) { throw new ClaimWrongStatusException(claim); } claim.ClaimStatus = Claim.Status.CheckedIn; claim.CheckInDate = Now; Debug.Assert(claim.Character != null, "claim.Character != null"); MarkChanged(claim.Character); claim.Character.InGame = true; AddCommentImpl(claim, null, ".", true, CommentExtraAction.CheckedIn); await UnitOfWork.SaveChangesAsync(); await EmailService.Email( EmailHelpers.CreateClaimEmail <CheckedInEmal>(claim, ".", s => s.ClaimStatusChange, CommentExtraAction.ApproveByMaster, await UserRepository.GetById(CurrentUserId))); if (financeEmail != null) { await EmailService.Email(financeEmail); } }
private async Task <T> AddCommentWithEmail <T>(string commentText, Claim claim, bool isVisibleToPlayer, Func <UserSubscription, bool> predicate, Comment parentComment, CommentExtraAction?extraAction = null, IEnumerable <User> extraSubscriptions = null) where T : ClaimEmailModel, new() { var visibleToPlayerUpdated = isVisibleToPlayer && parentComment?.IsVisibleToPlayer != false; AddCommentImpl(claim, parentComment, commentText, visibleToPlayerUpdated, extraAction); var extraRecipients = new[] { parentComment?.Author, parentComment?.Finance?.PaymentType?.User }. Union(extraSubscriptions ?? Enumerable.Empty <User>()); bool mastersOnly = !visibleToPlayerUpdated; return (EmailHelpers.CreateClaimEmail <T>(claim, commentText, predicate, extraAction, await UserRepository.GetById(CurrentUserId), mastersOnly, extraRecipients)); }
public async Task SaveFieldsFromClaim(int projectId, int characterId, IReadOnlyDictionary<int, string?> newFieldValue) { //TODO: Prevent lazy load here - use repository var claim = await LoadProjectSubEntityAsync<Claim>(projectId, characterId); var updatedFields = FieldSaveHelper.SaveCharacterFields(CurrentUserId, claim, newFieldValue, FieldDefaultValueGenerator); if (updatedFields.Any(f => f.Field.FieldBoundTo == FieldBoundTo.Character) && claim.Character != null) { MarkChanged(claim.Character); } var user = await GetCurrentUser(); var email = EmailHelpers.CreateFieldsEmail(claim, s => s.FieldChange, user, updatedFields); await UnitOfWork.SaveChangesAsync(); await EmailService.Email(email); }
public async Task <AccommodationRequest> SetAccommodationType(int projectId, int claimId, int roomTypeId) { //todo set first state to Unanswered var claim = await ClaimsRepository.GetClaim(projectId, claimId).ConfigureAwait(false); claim = claim.RequestAccess(CurrentUserId, acl => acl.CanSetPlayersAccommodations, claim?.ClaimStatus == Claim.Status.Approved ? ExtraAccessReason.PlayerOrResponsible : ExtraAccessReason.None); // Player cannot change accommodation type if already checked in if (claim.AccommodationRequest?.AccommodationTypeId == roomTypeId) { return(claim.AccommodationRequest); } var newType = await UnitOfWork.GetDbSet <ProjectAccommodationType>().FindAsync(roomTypeId) .ConfigureAwait(false); if (newType == null) { throw new JoinRpgEntityNotFoundException(roomTypeId, nameof(ProjectAccommodationType)); } var email = EmailHelpers.CreateFieldsEmail(claim, s => s.AccommodationChange, await GetCurrentUser(), new FieldWithPreviousAndNewValue[] { }, new Dictionary <string, PreviousAndNewValue>() { { "Тип поселения", //TODO[Localize] new PreviousAndNewValue(newType.Name, claim.AccommodationRequest?.AccommodationType.Name) }, }); var leaveEmail = await ConsiderLeavingRoom(claim); var accommodationRequest = new AccommodationRequest { ProjectId = projectId, Subjects = new List <Claim> { claim }, AccommodationTypeId = roomTypeId, IsAccepted = AccommodationRequest.InviteState.Accepted, }; UnitOfWork .GetDbSet <AccommodationRequest>() .Add(accommodationRequest); await UnitOfWork.SaveChangesAsync().ConfigureAwait(false); await EmailService.Email(email); if (leaveEmail != null) { await EmailService.Email(leaveEmail); } return(accommodationRequest); }
protected async Task <FinanceOperationEmail> AcceptFeeImpl(string contents, DateTime operationDate, int feeChange, int money, PaymentType paymentType, Claim claim) { paymentType.EnsureActive(); if (operationDate > Now.AddDays(1) ) //TODO[UTC]: if everyone properly uses UTC, we don't have to do +1 { throw new CannotPerformOperationInFuture(); } if (feeChange != 0 || money < 0) { claim.RequestMasterAccess(CurrentUserId, acl => acl.CanManageMoney); } var state = FinanceOperationState.Approved; if (paymentType.UserId != CurrentUserId) { if (claim.PlayerUserId == CurrentUserId) { //Player mark that he pay fee. Put this to moderation state = FinanceOperationState.Proposed; } else { claim.RequestMasterAccess(CurrentUserId, acl => acl.CanManageMoney); } } var comment = AddCommentImpl(claim, null, contents, isVisibleToPlayer: true, extraAction: null); var financeOperation = new FinanceOperation() { Created = Now, FeeChange = feeChange, MoneyAmount = money, Changed = Now, Claim = claim, Comment = comment, PaymentType = paymentType, State = state, ProjectId = claim.ProjectId, OperationDate = operationDate }; comment.Finance = financeOperation; claim.FinanceOperations.Add(financeOperation); claim.UpdateClaimFeeIfRequired(operationDate); var email = EmailHelpers.CreateClaimEmail <FinanceOperationEmail>(claim, contents, s => s.MoneyOperation, commentExtraAction: null, initiator: await UserRepository.GetById(CurrentUserId), extraRecipients: new[] { paymentType.User }); email.FeeChange = feeChange; email.Money = money; return(email); }
public async Task <int> MoveToSecondRole(int projectId, int claimId, int characterId) { var oldClaim = (await ClaimsRepository.GetClaim(projectId, claimId)).RequestAccess(CurrentUserId); //TODO Specific right oldClaim.EnsureStatus(Claim.Status.CheckedIn); Debug.Assert(oldClaim.Character != null, "oldClaim.Character != null"); oldClaim.Character.InGame = false; MarkChanged(oldClaim.Character); var source = await CharactersRepository.GetCharacterAsync(projectId, characterId); MarkChanged(source); EnsureCanAddClaim(oldClaim.PlayerUserId, source); var responsibleMaster = source.GetResponsibleMasters().FirstOrDefault(); var claim = new Claim() { CharacterGroupId = null, CharacterId = characterId, ProjectId = projectId, PlayerUserId = oldClaim.PlayerUserId, PlayerAcceptedDate = Now, CreateDate = Now, ClaimStatus = Claim.Status.Approved, CurrentFee = 0, ResponsibleMasterUserId = responsibleMaster?.UserId, ResponsibleMasterUser = responsibleMaster, LastUpdateDateTime = Now, MasterAcceptedDate = Now, CommentDiscussion = new CommentDiscussion() { CommentDiscussionId = -1, ProjectId = projectId }, }; claim.CommentDiscussion.Comments.Add(new Comment { CommentDiscussionId = -1, AuthorUserId = CurrentUserId, CommentText = new CommentText { Text = new MarkdownString(".") }, CreatedAt = Now, IsCommentByPlayer = false, IsVisibleToPlayer = true, ProjectId = projectId, LastEditTime = Now, ExtraAction = CommentExtraAction.SecondRole }); oldClaim.ClaimStatus = Claim.Status.Approved; source.ApprovedClaim = claim; AddCommentImpl(oldClaim, null, ".", true, CommentExtraAction.OutOfGame); UnitOfWork.GetDbSet <Claim>().Add(claim); var updatedFields = FieldSaveHelper.SaveCharacterFields(CurrentUserId, claim, new Dictionary <int, string>(), FieldDefaultValueGenerator); var claimEmail = EmailHelpers.CreateClaimEmail <SecondRoleEmail>(claim, "", s => s.ClaimStatusChange, CommentExtraAction.NewClaim, await UserRepository.GetById(CurrentUserId)); await UnitOfWork.SaveChangesAsync(); await EmailService.Email(claimEmail); return(claim.ClaimId); }