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);
            }
        }
예제 #2
0
        //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);
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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)));
        }
예제 #5
0
        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);
            }
        }
예제 #6
0
        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));
        }
예제 #7
0
        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);
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }