func()

in internal/service/question_common/question.go [704:829]


func (qs *QuestionCommon) UpdateQuestionLink(ctx context.Context, questionID, answerID, parsedText, originalText string) (string, error) {
	err := qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{
		FromQuestionID: uid.DeShortID(questionID),
		FromAnswerID:   uid.DeShortID(answerID),
	})
	if err != nil {
		return parsedText, err
	}
	// Update the number of question links that have been removed
	linkedQuestionIDs, err := qs.questionRepo.GetLinkedQuestionIDs(ctx, uid.DeShortID(questionID), entity.QuestionLinkStatusDeleted)
	if err != nil {
		log.Errorf("get linked question ids error %v", err)
	} else {
		for _, id := range linkedQuestionIDs {
			if err := qs.questionRepo.UpdateQuestionLinkCount(ctx, id); err != nil {
				log.Errorf("update question link count error %v", err)
			}
		}
	}

	links := checker.GetQuestionLink(originalText)
	if len(links) == 0 {
		return parsedText, nil
	}

	// get answer ids and question ids
	answerIDs := make([]string, 0, len(links))
	questionIDs := make([]string, 0, len(links))
	for _, link := range links {
		if link.AnswerID != "" {
			answerIDs = append(answerIDs, link.AnswerID)
		}
		if link.QuestionID != "" {
			questionIDs = append(questionIDs, link.QuestionID)
		}
	}

	// get answer info and build cache
	answerInfoList, err := qs.answerRepo.GetByIDs(ctx, answerIDs...)
	if err != nil {
		return parsedText, err
	}
	answerCache := make(map[string]string, len(answerInfoList))
	for _, ans := range answerInfoList {
		answerID := uid.DeShortID(ans.ID)
		questionID := ans.QuestionID
		answerCache[answerID] = questionID
	}

	// get question info and build cache
	questionInfoList, err := qs.questionRepo.FindByID(ctx, questionIDs)
	if err != nil {
		return parsedText, err
	}
	questionCache := make(map[string]struct{}, len(questionInfoList))
	for _, q := range questionInfoList {
		questionID := uid.DeShortID(q.ID)
		questionCache[questionID] = struct{}{}
	}

	// process links and generate new QuestionLink
	validLinks := make([]*entity.QuestionLink, 0, len(links))
	for _, link := range links {
		linkQuestionID := uid.DeShortID(link.QuestionID)
		linkAnswerID := uid.DeShortID(link.AnswerID)
		// validate question id
		if _, exists := questionCache[linkQuestionID]; linkQuestionID != "0" && !exists {
			continue
		}

		// validate answer id
		if linkAnswerID != "0" {
			linkedQuestionID, exists := answerCache[linkAnswerID]
			if !exists {
				continue
			}
			// if question id is empty, get it from answer cache
			if link.QuestionID == "" {
				link.QuestionID = linkedQuestionID
			}
		}

		// build new link
		newLink := &entity.QuestionLink{
			FromQuestionID: uid.DeShortID(questionID),
			FromAnswerID:   uid.DeShortID(answerID),
			ToQuestionID:   uid.DeShortID(link.QuestionID),
			ToAnswerID:     uid.DeShortID(link.AnswerID),
		}
		// replace link in parsed text
		if link.QuestionID != "" {
			htmlLink := fmt.Sprintf("<a href=\"/questions/%s\">#%s</a>", link.QuestionID, link.QuestionID)
			parsedText = strings.ReplaceAll(parsedText, "#"+link.QuestionID, htmlLink)
		}
		if link.AnswerID != "" {
			linkedQuestionID := answerCache[linkAnswerID]
			htmlLink := fmt.Sprintf("<a href=\"/questions/%s/%s\">#%s</a>", linkedQuestionID, link.AnswerID, link.AnswerID)
			parsedText = strings.ReplaceAll(parsedText, "#"+link.AnswerID, htmlLink)
			newLink.ToQuestionID = uid.DeShortID(linkedQuestionID)
		}
		// avoid link to self
		if newLink.FromQuestionID != newLink.ToQuestionID {
			validLinks = append(validLinks, newLink)
		}
	}

	// add new links to repo
	if len(validLinks) > 0 {
		err = qs.questionRepo.LinkQuestion(ctx, validLinks...)
		if err != nil {
			return parsedText, err
		}
	}

	// update question linked count
	for _, link := range validLinks {
		if len(link.ToQuestionID) == 0 {
			continue
		}
		if err := qs.questionRepo.UpdateQuestionLinkCount(ctx, link.ToQuestionID); err != nil {
			log.Errorf("update question link count error %v", err)
		}
	}

	return parsedText, nil
}