예제 #1
0
 public CannedReply(CannedReplyAnswer cra)
 {
     Id                 = cra.Id;
     MerchantId         = cra.MerchantId;
     UserId             = cra.UserId;
     CategoryName       = cra.CategoryName;
     ReplyContent       = cra.ReplyContent;
     IsAutoReplyEnabled = cra.IsAutoReplyEnabled;
     CreationTime       = cra.CreationTime;
     Questions          = cra.CannedReplyQuestions?.Select(crq => crq.Question) ?? Enumerable.Empty <string>();
 }
예제 #2
0
        // DELETE: odata/CannedReplies(5)
        public async Task <string> Delete(long key)
        {
            CannedReplyAnswer cannedReplyAnswer = await Db.CannedReplyAnswers.Include(c => c.CannedReplyQuestions).SingleOrDefaultAsync(c => c.Id == key);

            if (cannedReplyAnswer == null)
            {
                return("404");
            }
            Db.CannedReplyQuestions.RemoveRange(cannedReplyAnswer.CannedReplyQuestions);
            Db.CannedReplyAnswers.Remove(cannedReplyAnswer);
            await Db.SaveChangesAsync();

            return("");
        }
예제 #3
0
        private async Task <List <long> > AttachQuestionsToAnswerAndSaveInDb(CannedReplyAnswer cannedReplyAnswer, IEnumerable <string> targetQuestions)
        {
            List <long> specialQuestionIdLst = new List <long>();

            if (targetQuestions != null)
            {
                var targetQuestionsHashSet = new HashSet <string>(targetQuestions);
                if (targetQuestionsHashSet.Any())
                {
                    specialQuestionIdLst = await AddQuestionsToAnswerAndNotSaveInDb(cannedReplyAnswer, targetQuestionsHashSet);

                    await Db.SaveChangesAsync();
                }
            }
            return(specialQuestionIdLst);
        }
예제 #4
0
        private async Task <List <long> > AddQuestionsToAnswerAndNotSaveInDb(CannedReplyAnswer cannedReplyAnswer, HashSet <string> targetQuestions)
        {
            //these question ids in this lst will not be inserted
            List <long> specialQuestionIdLst = new List <long>();

            if (targetQuestions != null)
            {
                foreach (var question in targetQuestions)
                {
                    string csQuestion  = CannedReply.GetMd5Hash(question);
                    var    crqFromDbId = await Db.CannedReplyQuestions.Where(c => c.CS_Question == csQuestion &&
                                                                             c.MerchantId == cannedReplyAnswer.MerchantId &&
                                                                             c.UserId == cannedReplyAnswer.UserId)
                                         .Where(c => c.Question == question)
                                         .Select(c => c.Id)
                                         .FirstOrDefaultAsync();

                    if (crqFromDbId == 0)
                    {
                        Db.CannedReplyQuestions.Add(new CannedReplyQuestion(cannedReplyAnswer, question));
                    }
                    else
                    {
                        //Instead of update, we choose skip

                        /*
                         * if (crqFromDb.CannedReplyAnswerId != cannedReplyAnswer.Id)
                         * {
                         *  crqFromDb.CannedReplyAnswerId = cannedReplyAnswer.Id;
                         * }
                         */
                        specialQuestionIdLst.Add(crqFromDbId);
                    }
                    //We don't need this line unless we choose update instead of skip
                    //await Db.SaveChangesAsync();
                }
            }
            return(specialQuestionIdLst);
        }
예제 #5
0
        private async Task <CannedReply.CannedReplyAnswerInternalResult> UpdateCannedReplyAnswerToDb(CannedReply cannedReply)
        {
            var curMerchantIdFromDb = await Db.Merchants.Select(m => m.Id).FirstOrDefaultAsync(m => m == cannedReply.MerchantId);

            if (curMerchantIdFromDb == 0)
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = null,
                    Status = "Error",
                    ErrorMessage = "MerchantId is not valid or There is no such MerchantId in DB."
                });
            }
            CannedReplyAnswer craFromDb = await Db.CannedReplyAnswers.Include(c => c.CannedReplyQuestions).SingleOrDefaultAsync(c => c.Id == cannedReply.Id);

            if (craFromDb == null)
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = null,
                    Status = "Error",
                    ErrorMessage = "record not found in DB"
                });
            }

            craFromDb.ReplyContent = cannedReply.ReplyContent ?? craFromDb.ReplyContent;
            string            csReplyContent          = CannedReply.GetMd5Hash(craFromDb.ReplyContent);
            CannedReplyAnswer craFromDbWithSameAnswer = await Db.CannedReplyAnswers.Where(c => c.CS_ReplyContent == csReplyContent &&
                                                                                          c.MerchantId == craFromDb.MerchantId &&
                                                                                          c.UserId == craFromDb.UserId &&
                                                                                          c.Id != craFromDb.Id)
                                                        .Include(c => c.CannedReplyQuestions)
                                                        .FirstOrDefaultAsync(c => c.ReplyContent == craFromDb.ReplyContent);

            if (craFromDbWithSameAnswer == null)
            {
                craFromDb.IsAutoReplyEnabled = cannedReply.IsAutoReplyEnabled;
                craFromDb.CategoryName       = cannedReply.CategoryName ?? craFromDb.CategoryName;
                try
                {
                    if (cannedReply.Questions != null)
                    {
                        List <long> specialQuestionIdLst = await ForceAttachWithNewQuestionsToAnswerAndNotSaveInDb(craFromDb, cannedReply.Questions);

                        await Db.SaveChangesAsync();

                        if (specialQuestionIdLst.Any())
                        {
                            return(new CannedReply.CannedReplyAnswerInternalResult
                            {
                                CannedReplyAnswer = craFromDb,
                                Status = "UpdatedWithSkip",
                                ErrorMessage = $"Questions are skipped because this answer or other answers have these questions, questionIds: {string.Join(",", specialQuestionIdLst)}",
                                //Status = "UpdateWithForceUpdate",
                                //ErrorMessage = $"Questions are updated with this new answer, questionIds: {string.Join(",", specialQuestionIdLst)}",
                                QuestionIds = specialQuestionIdLst
                            });
                        }
                        else
                        {
                            return(new CannedReply.CannedReplyAnswerInternalResult
                            {
                                CannedReplyAnswer = craFromDb,
                                Status = "Updated",
                                ErrorMessage = ""
                            });
                        }
                    }
                    else
                    {
                        await Db.SaveChangesAsync();

                        return(new CannedReply.CannedReplyAnswerInternalResult
                        {
                            CannedReplyAnswer = craFromDb,
                            Status = "Updated",
                            ErrorMessage = ""
                        });
                    }
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    if (!CannedReplyExists(cannedReply.Id))
                    {
                        return(new CannedReply.CannedReplyAnswerInternalResult
                        {
                            CannedReplyAnswer = null,
                            Status = "Error",
                            ErrorMessage = "record not found in DB"
                        });
                    }
                    else
                    {
                        return(new CannedReply.CannedReplyAnswerInternalResult
                        {
                            CannedReplyAnswer = null,
                            Status = "Error",
                            ErrorMessage = ex.Message + ex.StackTrace
                        });
                    }
                }
                catch (Exception ex)
                {
                    ex = GetInnerException(ex);
                    return(new CannedReply.CannedReplyAnswerInternalResult
                    {
                        CannedReplyAnswer = null,
                        Status = "Error",
                        ErrorMessage = ex.Message + ex.StackTrace
                    });
                }
            }
            else
            {
                cannedReply.CategoryName = cannedReply.CategoryName ?? craFromDb.CategoryName;
                if (cannedReply.Questions == null)
                {
                    var mergeResult = await MergeExistingQuestionsToExistingAnswerInDb(craFromDb, craFromDbWithSameAnswer);

                    Db.CannedReplyAnswers.Remove(craFromDb);
                    await Db.SaveChangesAsync();

                    return(mergeResult);
                }
                else
                {
                    Db.CannedReplyQuestions.RemoveRange(craFromDb.CannedReplyQuestions);
                    Db.CannedReplyAnswers.Remove(craFromDb);
                    await Db.SaveChangesAsync();

                    return(await MergeCannedReplyToExistingAnswerInDb(cannedReply, craFromDbWithSameAnswer));
                }
            }
        }
예제 #6
0
        private async Task <CannedReply.CannedReplyAnswerInternalResult> CreateCannedReplyAnswerToDb(CannedReply cannedReply)
        {
            var curMerchantIdFromDb = await Db.Merchants.Select(m => m.Id).FirstOrDefaultAsync(m => m == cannedReply.MerchantId);

            if (curMerchantIdFromDb == 0)
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = null,
                    Status = "Error",
                    ErrorMessage = "MerchantId is not valid or There is no such MerchantId in DB."
                });
            }
            if (cannedReply.Questions == null || !cannedReply.Questions.Any())
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = null,
                    Status = "Error",
                    ErrorMessage = "No questions to Add when creat canned Reply."
                });
            }
            string            csReplyContent = CannedReply.GetMd5Hash(cannedReply.ReplyContent);
            CannedReplyAnswer craFromDb      = await Db.CannedReplyAnswers.Where(c => c.CS_ReplyContent == csReplyContent &&
                                                                                 c.MerchantId == cannedReply.MerchantId &&
                                                                                 c.UserId == cannedReply.UserId)
                                               .Include(c => c.CannedReplyQuestions)
                                               .FirstOrDefaultAsync(c => c.ReplyContent == cannedReply.ReplyContent);

            if (craFromDb != null)
            {
                cannedReply.CategoryName = cannedReply.CategoryName ?? "";
                return(await MergeCannedReplyToExistingAnswerInDb(cannedReply, craFromDb));
            }
            else
            {
                try
                {
                    CannedReplyAnswer cannedReplyAnswer = new CannedReplyAnswer(cannedReply);
                    Db.CannedReplyAnswers.Add(cannedReplyAnswer);
                    await Db.SaveChangesAsync();

                    //these question ids in this lst will not be inserted
                    List <long> specialQuestionIdLst = await AttachQuestionsToAnswerAndSaveInDb(cannedReplyAnswer, cannedReply.Questions);

                    if (specialQuestionIdLst.Any())
                    {
                        if (specialQuestionIdLst.Count == new HashSet <string>(cannedReply.Questions).Count)
                        {
                            //TODO: backend job to clean these answers if transaction failed
                            Db.CannedReplyAnswers.Remove(cannedReplyAnswer);
                            await Db.SaveChangesAsync();

                            return(new CannedReply.CannedReplyAnswerInternalResult
                            {
                                CannedReplyAnswer = null,
                                Status = "Error",
                                ErrorMessage = "No questions to Add or all questions are duplicated when creating canned Reply."
                            });
                        }
                        return(new CannedReply.CannedReplyAnswerInternalResult
                        {
                            CannedReplyAnswer = cannedReplyAnswer,
                            Status = "CreatedWithSkip",
                            ErrorMessage = $"Questions are skipped because this answer or other answers have these questions, questionIds: {string.Join(",", specialQuestionIdLst)}",
                            //Status = "CreatedWithUpdate",
                            //ErrorMessage = $"Questions are updated to be attached with this new answer, questionIds: {string.Join(",", specialQuestionIdLst)}",
                            QuestionIds = specialQuestionIdLst
                        });
                    }
                    else
                    {
                        return(new CannedReply.CannedReplyAnswerInternalResult
                        {
                            CannedReplyAnswer = cannedReplyAnswer,
                            Status = "Created",
                            ErrorMessage = ""
                        });
                    }
                }
                catch (Exception ex)
                {
                    ex = GetInnerException(ex);
                    return(new CannedReply.CannedReplyAnswerInternalResult
                    {
                        CannedReplyAnswer = null,
                        Status = "Error",
                        ErrorMessage = ex.Message + ex.StackTrace
                    });
                }
            }
        }
예제 #7
0
        private async Task <CannedReply.CannedReplyAnswerInternalResult> MergeExistingQuestionsToExistingAnswerInDb(CannedReplyAnswer craFromDbOri, CannedReplyAnswer craFromDbWithSameAnswerDes)
        {
            craFromDbOri.CannedReplyQuestions.ForEach(crq => crq.CannedReplyAnswerId = craFromDbWithSameAnswerDes.Id);
            await Db.SaveChangesAsync();

            return(new CannedReply.CannedReplyAnswerInternalResult
            {
                CannedReplyAnswer = craFromDbWithSameAnswerDes,
                Status = "Updated",
                ErrorMessage = $"Merged Questions of Answer {craFromDbOri.Id} to Answer {craFromDbWithSameAnswerDes.Id}"
            });
        }
예제 #8
0
        private async Task <CannedReply.CannedReplyAnswerInternalResult> MergeCannedReplyToExistingAnswerInDb(CannedReply cannedReply, CannedReplyAnswer craFromDb)
        {
            craFromDb.IsAutoReplyEnabled = cannedReply.IsAutoReplyEnabled;
            craFromDb.CategoryName       = cannedReply.CategoryName ?? craFromDb.CategoryName;
            //don't use this if we have changes on CannedReply's dependency,
            //we may lose info in the CannedReply after it's dependency get changed by this operation.
            //Here I remove it just because it is no needed,
            //await Db.SaveChangesAsync();
            List <long> specialQuestionIdLst = await AttachQuestionsToAnswerAndSaveInDb(craFromDb, cannedReply.Questions);

            if (specialQuestionIdLst.Any())
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = craFromDb,
                    Status = "UpdatedWithSkip",
                    ErrorMessage = $"Merged Questions to Answer {craFromDb.Id}. Questions are skipped because this answer or other answers have these questions, questionIds: {string.Join(",", specialQuestionIdLst)}",
                    //Status = "UpdateWithForceUpdate",
                    //ErrorMessage = $"Questions are updated with this new answer, questionIds: {string.Join(",", specialQuestionIdLst)}",
                    QuestionIds = specialQuestionIdLst
                });
            }
            else
            {
                return(new CannedReply.CannedReplyAnswerInternalResult
                {
                    CannedReplyAnswer = craFromDb,
                    Status = "Updated",
                    ErrorMessage = $"Merged Questions to Answer {craFromDb.Id}"
                });
            }
        }
예제 #9
0
        private async Task <List <long> > ForceAttachWithNewQuestionsToAnswerAndNotSaveInDb(CannedReplyAnswer cannedReplyAnswer, IEnumerable <string> targetQuestions)
        {
            if (targetQuestions == null)
            {
                throw new Exception("Error: not set question parameter when trying to update questions");
            }
            Dictionary <string, CannedReplyQuestion> oriQuestionDict = new Dictionary <string, CannedReplyQuestion>();

            cannedReplyAnswer.CannedReplyQuestions.ForEach(crq =>
            {
                if (!oriQuestionDict.ContainsKey(crq.Question))
                {
                    oriQuestionDict.Add(crq.Question, crq);
                }
            });
            HashSet <string> oriQuestionSet = new HashSet <string>(cannedReplyAnswer.CannedReplyQuestions.Select(crq => crq.Question));
            HashSet <string> desQuestionSet = new HashSet <string>(targetQuestions);
            HashSet <string> innerSet       = new HashSet <string>(oriQuestionSet);

            innerSet.IntersectWith(desQuestionSet);
            oriQuestionSet.ExceptWith(innerSet);
            desQuestionSet.ExceptWith(innerSet);
            foreach (var deleteQuestion in oriQuestionSet)
            {
                //this may throw error when save, because there may be multiple thread trying to update or delete
                Db.CannedReplyQuestions.Remove(oriQuestionDict[deleteQuestion]);
            }
            //these question ids in this lst will not be inserted
            List <long> specialQuestionIdLst = await AddQuestionsToAnswerAndNotSaveInDb(cannedReplyAnswer, desQuestionSet);

            if (specialQuestionIdLst.Count == desQuestionSet.Count && innerSet.Count == 0)
            {
                throw new Exception("Error: all questions have existing answer when trying to update this answer's questions");
            }
            //await Db.SaveChangesAsync();
            return(specialQuestionIdLst);
        }