This is an automated email from the ASF dual-hosted git repository.

linkinstar pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/answer.git

commit 9154b9ba5b04329171b8dd6c8cf5c8475e8762c5
Author: Dinesht04 <[email protected]>
AuthorDate: Fri Oct 17 16:48:22 2025 +0530

    feat(ui,internal): add optional question body
---
 i18n/en_US.yaml                              |  9 +++++--
 internal/base/reason/reason.go               |  1 +
 internal/schema/question_schema.go           | 26 +++---------------
 internal/service/content/question_service.go | 40 ++++++++++++++++++++++++++++
 internal/service/question_common/question.go |  8 ++++++
 ui/src/pages/Questions/Ask/index.tsx         | 26 ++++++++++++++----
 6 files changed, 80 insertions(+), 30 deletions(-)

diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 5f694ea2..91bfa2af 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -235,6 +235,8 @@ backend:
         other: No permission to update.
       content_cannot_empty:
         other: Content cannot be empty.
+      content_less_than_minumum:
+        other: Not enough content entered.
     rank:
       fail_to_meet_the_condition:
         other: Reputation rank fail to meet the condition.
@@ -1160,6 +1162,9 @@ ui:
           label: Body
           msg:
             empty: Body cannot be empty.
+          hint:
+            optional_body: Share what the question is about.
+            minimum_characters: "Share what the question is about, at least {{ 
min_content_length }} characters are required."
         tags:
           label: Tags
           msg:
@@ -1181,8 +1186,8 @@ ui:
     add_btn: Add tag
     create_btn: Create new tag
     search_tag: Search tag
-    hint: "Describe what your content is about, at least one tag is required."
-    hint_zero_tags: " Describe what your content is about."
+    hint: Describe what your content is about, at least one tag is required.
+    hint_zero_tags: Describe what your content is about.
     hint_more_than_one_tag: "Describe what your content is about, at least {{ 
min_tags_number }} tags are required."
     no_result: No tags matched
     tag_required_text: Required tag (at least one)
diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go
index 5a34d921..42e29f4c 100644
--- a/internal/base/reason/reason.go
+++ b/internal/base/reason/reason.go
@@ -47,6 +47,7 @@ const (
        QuestionAlreadyDeleted           = "error.question.already_deleted"
        QuestionUnderReview              = "error.question.under_review"
        QuestionContentCannotEmpty       = "error.question.content_cannot_empty"
+       QuestionContentLessThanMinimum   = 
"error.question.content_less_than_minumum"
        AnswerNotFound                   = "error.answer.not_found"
        AnswerCannotDeleted              = "error.answer.cannot_deleted"
        AnswerCannotUpdate               = "error.answer.cannot_update"
diff --git a/internal/schema/question_schema.go 
b/internal/schema/question_schema.go
index 5092ddf8..84b97b83 100644
--- a/internal/schema/question_schema.go
+++ b/internal/schema/question_schema.go
@@ -79,7 +79,7 @@ type QuestionAdd struct {
        // question title
        Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
        // content
-       Content string `validate:"required,notblank,gte=6,lte=65535" 
json:"content"`
+       Content string `validate:"gte=0,lte=65535" json:"content"`
        // html
        HTML string `json:"-"`
        // tags
@@ -100,12 +100,6 @@ func (req *QuestionAdd) Check() (errFields 
[]*validator.FormErrorField, err erro
                        tag.ParsedText = 
converter.Markdown2HTML(tag.OriginalText)
                }
        }
-       if req.HTML == "" {
-               return append(errFields, &validator.FormErrorField{
-                       ErrorField: "content",
-                       ErrorMsg:   reason.QuestionContentCannotEmpty,
-               }), errors.BadRequest(reason.QuestionContentCannotEmpty)
-       }
        return nil, nil
 }
 
@@ -113,7 +107,7 @@ type QuestionAddByAnswer struct {
        // question title
        Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
        // content
-       Content string `validate:"required,notblank,gte=6,lte=65535" 
json:"content"`
+       Content string `validate:"gte=0,lte=65535" json:"content"`
        // html
        HTML          string `json:"-"`
        AnswerContent string `validate:"required,notblank,gte=6,lte=65535" 
json:"answer_content"`
@@ -138,19 +132,11 @@ func (req *QuestionAddByAnswer) Check() (errFields 
[]*validator.FormErrorField,
                        tag.ParsedText = 
converter.Markdown2HTML(tag.OriginalText)
                }
        }
-       if req.HTML == "" {
-               errFields = append(errFields, &validator.FormErrorField{
-                       ErrorField: "content",
-                       ErrorMsg:   reason.QuestionContentCannotEmpty,
-               })
-       }
        if req.AnswerHTML == "" {
                errFields = append(errFields, &validator.FormErrorField{
                        ErrorField: "answer_content",
                        ErrorMsg:   reason.AnswerContentCannotEmpty,
                })
-       }
-       if req.HTML == "" || req.AnswerHTML == "" {
                return errFields, 
errors.BadRequest(reason.QuestionContentCannotEmpty)
        }
        return nil, nil
@@ -195,7 +181,7 @@ type QuestionUpdate struct {
        // question title
        Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
        // content
-       Content string `validate:"required,notblank,gte=6,lte=65535" 
json:"content"`
+       Content string `validate:"gte=0,lte=65535" json:"content"`
        // html
        HTML       string   `json:"-"`
        InviteUser []string `validate:"omitempty"  json:"invite_user"`
@@ -227,12 +213,6 @@ type QuestionUpdateInviteUser struct {
 
 func (req *QuestionUpdate) Check() (errFields []*validator.FormErrorField, err 
error) {
        req.HTML = converter.Markdown2HTML(req.Content)
-       if req.HTML == "" {
-               return append(errFields, &validator.FormErrorField{
-                       ErrorField: "content",
-                       ErrorMsg:   reason.QuestionContentCannotEmpty,
-               }), errors.BadRequest(reason.QuestionContentCannotEmpty)
-       }
        return nil, nil
 }
 
diff --git a/internal/service/content/question_service.go 
b/internal/service/content/question_service.go
index 6832437d..1d1d1af3 100644
--- a/internal/service/content/question_service.go
+++ b/internal/service/content/question_service.go
@@ -242,6 +242,19 @@ func (qs *QuestionService) CheckAddQuestion(ctx 
context.Context, req *schema.Que
                err = errors.BadRequest(reason.TagMinCount)
                return errorlist, err
        }
+       minimumContentLength, err := 
qs.questioncommon.GetMinimumContentLength(ctx)
+       if err != nil {
+               return
+       }
+       if len(req.Content) < minimumContentLength {
+               errorlist := make([]*validator.FormErrorField, 0)
+               errorlist = append(errorlist, &validator.FormErrorField{
+                       ErrorField: "content",
+                       ErrorMsg:   translator.Tr(handler.GetLangByCtx(ctx), 
reason.QuestionContentLessThanMinimum),
+               })
+               err = errors.BadRequest(reason.QuestionContentLessThanMinimum)
+               return errorlist, err
+       }
        recommendExist, err := qs.tagCommon.ExistRecommend(ctx, req.Tags)
        if err != nil {
                return
@@ -301,6 +314,19 @@ func (qs *QuestionService) AddQuestion(ctx 
context.Context, req *schema.Question
                err = errors.BadRequest(reason.TagMinCount)
                return errorlist, err
        }
+       minimumContentLength, err := 
qs.questioncommon.GetMinimumContentLength(ctx)
+       if err != nil {
+               return
+       }
+       if len(req.Content) < minimumContentLength {
+               errorlist := make([]*validator.FormErrorField, 0)
+               errorlist = append(errorlist, &validator.FormErrorField{
+                       ErrorField: "content",
+                       ErrorMsg:   translator.Tr(handler.GetLangByCtx(ctx), 
reason.QuestionContentLessThanMinimum),
+               })
+               err = errors.BadRequest(reason.QuestionContentLessThanMinimum)
+               return errorlist, err
+       }
        recommendExist, err := qs.tagCommon.ExistRecommend(ctx, req.Tags)
        if err != nil {
                return
@@ -907,6 +933,20 @@ func (qs *QuestionService) UpdateQuestion(ctx 
context.Context, req *schema.Quest
        question.UserID = dbinfo.UserID
        question.LastEditUserID = req.UserID
 
+       minimumContentLength, err := 
qs.questioncommon.GetMinimumContentLength(ctx)
+       if err != nil {
+               return
+       }
+       if len(req.Content) < minimumContentLength {
+               errorlist := make([]*validator.FormErrorField, 0)
+               errorlist = append(errorlist, &validator.FormErrorField{
+                       ErrorField: "content",
+                       ErrorMsg:   translator.Tr(handler.GetLangByCtx(ctx), 
reason.QuestionContentLessThanMinimum),
+               })
+               err = errors.BadRequest(reason.QuestionContentLessThanMinimum)
+               return errorlist, err
+       }
+
        oldTags, tagerr := qs.tagCommon.GetObjectEntityTag(ctx, question.ID)
        if tagerr != nil {
                return questionInfo, tagerr
diff --git a/internal/service/question_common/question.go 
b/internal/service/question_common/question.go
index 92392048..feb5626e 100644
--- a/internal/service/question_common/question.go
+++ b/internal/service/question_common/question.go
@@ -899,3 +899,11 @@ func (qs *QuestionCommon) tryToGetQuestionIDFromMsg(ctx 
context.Context, closeMs
        questionID = uid.DeShortID(questionID)
        return questionID
 }
+
+func (qs *QuestionCommon) GetMinimumContentLength(ctx context.Context) (int, 
error) {
+       siteInfo, err := qs.siteInfoService.GetSiteWrite(ctx)
+       if err != nil {
+               return 6, err
+       }
+       return siteInfo.MinimumContent, nil
+}
diff --git a/ui/src/pages/Questions/Ask/index.tsx 
b/ui/src/pages/Questions/Ask/index.tsx
index 149373ed..d7804195 100644
--- a/ui/src/pages/Questions/Ask/index.tsx
+++ b/ui/src/pages/Questions/Ask/index.tsx
@@ -28,6 +28,7 @@ import isEqual from 'lodash/isEqual';
 import debounce from 'lodash/debounce';
 import fm from 'front-matter';
 
+import { writeSettingStore } from '@/stores';
 import { usePageTags, usePromptWithUnload } from '@/hooks';
 import { Editor, EditorRef, TagSelector } from '@/components';
 import type * as Type from '@/common/interface';
@@ -120,6 +121,7 @@ const Ask = () => {
       handleTagsChange(resp);
     });
   };
+  const writeInfo = writeSettingStore((state) => state.write);
 
   const isEdit = qid !== undefined;
 
@@ -423,6 +425,24 @@ const Ask = () => {
   usePageTags({
     title: pageTitle,
   });
+
+  const handleContentHint = () => {
+    if (
+      !writeInfo ||
+      writeInfo.min_content === undefined ||
+      !writeInfo.min_content
+    ) {
+      return t(`form.fields.body.hint.optional_body`);
+    }
+
+    let str: string = t(`form.fields.body.hint.minimum_characters`);
+    str = str.replace(
+      `{{ min_content_length }}`,
+      writeInfo.min_content.toString(),
+    );
+    return str;
+  };
+
   return (
     <div className="pt-4 mb-5">
       <h3 className="mb-4">{isEdit ? t('edit_title') : t('title')}</h3>
@@ -451,7 +471,6 @@ const Ask = () => {
                 </Form.Select>
               </Form.Group>
             )}
-
             <Form.Group controlId="title" className="mb-3">
               <Form.Label>{t('form.fields.title.label')}</Form.Label>
               <Form.Control
@@ -468,7 +487,6 @@ const Ask = () => {
               </Form.Control.Feedback>
               {bool && <SearchQuestion similarQuestions={similarQuestions} />}
             </Form.Group>
-
             <Form.Group controlId="content">
               <Form.Label>{t('form.fields.body.label')}</Form.Label>
               <Editor
@@ -487,11 +505,11 @@ const Ask = () => {
                 }}
                 ref={editorRef}
               />
+              <Form.Text>{handleContentHint()}</Form.Text>
               <Form.Control.Feedback type="invalid">
                 {formData.content.errorMsg}
               </Form.Control.Feedback>
             </Form.Group>
-
             <Form.Group controlId="tags" className="my-3">
               <Form.Label>{t('form.fields.tags.label')}</Form.Label>
               <TagSelector
@@ -503,7 +521,6 @@ const Ask = () => {
                 errMsg={formData.tags.errorMsg}
               />
             </Form.Group>
-
             {!isEdit && (
               <>
                 <Form.Switch
@@ -544,7 +561,6 @@ const Ask = () => {
                 )}
               </>
             )}
-
             {isEdit && (
               <Form.Group controlId="edit_summary" className="my-3">
                 <Form.Label>{t('form.fields.edit_summary.label')}</Form.Label>

Reply via email to