Skip to content

Commit

Permalink
not ready
Browse files Browse the repository at this point in the history
  • Loading branch information
hgaol committed Dec 11, 2023
1 parent 8e65774 commit b840399
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 25 deletions.
5 changes: 5 additions & 0 deletions i18n/en_US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ ui:
btn_accepted: Accepted
write_answer:
title: Your Answer
edit_answer: Edit my existing answer
btn_name: Post your answer
add_another_answer: Add another answer
confirm_title: Continue to answer
Expand Down Expand Up @@ -1642,6 +1643,10 @@ ui:
text: "You can add privacy policy content here. If you already have a document hosted elsewhere, provide the full URL here."
write:
page_title: Write
restrict_answer:
title: Restrict answer
label: Each user can only write one answer for each question
text: "They can use the edit link to refine and improve their existing answer, instead."
recommend_tags:
label: Recommend tags
text: "Please input tag slug above, one tag per line."
Expand Down
4 changes: 2 additions & 2 deletions internal/controller/answer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,12 @@ func (ac *AnswerController) Add(ctx *gin.Context) {
}
if write.RestrictAnswer {
// check if there's already an answer by this user
count, err := ac.answerService.GetCountByUserIDQuestionID(ctx, req.UserID, req.QuestionID)
ids, err := ac.answerService.GetCountByUserIDQuestionID(ctx, req.UserID, req.QuestionID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
}
if count >= 1 {
if len(ids) >= 1 {
handler.HandleResponse(ctx, errors.Forbidden(reason.AnswerRestrictAnswer), nil)
return
}
Expand Down
4 changes: 4 additions & 0 deletions internal/controller/siteinfo_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (sc *SiteInfoController) GetSiteInfo(ctx *gin.Context) {
if err != nil {
log.Error(err)
}
resp.Write, err = sc.siteInfoService.GetSiteWrite(ctx)
if err != nil {
log.Error(err)
}

handler.HandleResponse(ctx, nil, resp)
}
Expand Down
22 changes: 11 additions & 11 deletions internal/repo/answer/answer_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ func (ar *answerRepo) GetAnswer(ctx context.Context, id string) (

// GetQuestionCount
func (ar *answerRepo) GetAnswerCount(ctx context.Context) (count int64, err error) {
list := make([]*entity.Answer, 0)
count, err = ar.data.DB.Context(ctx).Where("status = ?", entity.AnswerStatusAvailable).FindAndCount(&list)
var resp = new(entity.Answer)
count, err = ar.data.DB.Context(ctx).Where("status = ?", entity.AnswerStatusAvailable).Count(resp)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
Expand Down Expand Up @@ -272,31 +272,31 @@ func (ar *answerRepo) GetByID(ctx context.Context, answerID string) (*entity.Ans

func (ar *answerRepo) GetCountByQuestionID(ctx context.Context, questionID string) (int64, error) {
questionID = uid.DeShortID(questionID)
rows := make([]*entity.Answer, 0)
count, err := ar.data.DB.Context(ctx).Where("question_id =? and status = ?", questionID, entity.AnswerStatusAvailable).FindAndCount(&rows)
var resp = new(entity.Answer)
count, err := ar.data.DB.Context(ctx).Where("question_id =? and status = ?", questionID, entity.AnswerStatusAvailable).Count(resp)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return count, nil
}

func (ar *answerRepo) GetCountByUserID(ctx context.Context, userID string) (int64, error) {
rows := make([]*entity.Answer, 0)
count, err := ar.data.DB.Context(ctx).Where(" user_id = ? and status = ?", userID, entity.AnswerStatusAvailable).FindAndCount(&rows)
var resp = new(entity.Answer)
count, err := ar.data.DB.Context(ctx).Where(" user_id = ? and status = ?", userID, entity.AnswerStatusAvailable).Count(resp)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return count, nil
}

func (ar *answerRepo) GetCountByUserIDQuestionID(ctx context.Context, userID string, questionID string) (count int64, err error) {
func (ar *answerRepo) GetIDsByUserIDAndQuestionID(ctx context.Context, userID string, questionID string) ([]int64, error) {
questionID = uid.DeShortID(questionID)
var resp = new(entity.Answer)
count, err = ar.data.DB.Context(ctx).Where("question_id =? and user_id = ? and status = ?", questionID, userID, entity.AnswerStatusAvailable).Count(resp)
var resp []int64
err := ar.data.DB.Context(ctx).Table(entity.Answer{}.TableName()).Where("question_id =? and user_id = ? and status = ?", questionID, userID, entity.AnswerStatusAvailable).OrderBy("created_at ASC").Cols("id").Find(&resp)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
return resp, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return count, nil
return resp, nil
}

// SearchList
Expand Down
3 changes: 2 additions & 1 deletion internal/schema/question_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ type QuestionInfo struct {
UpdateUserInfo *UserBasicInfo `json:"update_user_info,omitempty"`
LastAnsweredUserInfo *UserBasicInfo `json:"last_answered_user_info,omitempty"`
Answered bool `json:"answered"`
AnswerIDs []string `json:"answer_ids"`
Collected bool `json:"collected"`
VoteStatus string `json:"vote_status"`
IsFollowed bool `json:"is_followed"`
Expand All @@ -257,7 +258,7 @@ type QuestionInfo struct {
// UpdateQuestionResp update question resp
type UpdateQuestionResp struct {
UrlTitle string `json:"url_title"`
WaitForReview bool `json:"wait_for_review"`
WaitForReview bool `json:"wait_for_review"`
}

type AdminQuestionInfo struct {
Expand Down
1 change: 1 addition & 0 deletions internal/schema/siteinfo_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ type SiteInfoResp struct {
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
SiteSeo *SiteSeoResp `json:"site_seo"`
SiteUsers *SiteUsersResp `json:"site_users"`
Write *SiteWriteResp `json:"site_write"`
Version string `json:"version"`
Revision string `json:"revision"`
}
Expand Down
10 changes: 5 additions & 5 deletions internal/service/answer_common/answer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type AnswerRepo interface {
GetByID(ctx context.Context, answerID string) (*entity.Answer, bool, error)
GetCountByQuestionID(ctx context.Context, questionID string) (int64, error)
GetCountByUserID(ctx context.Context, userID string) (int64, error)
GetCountByUserIDQuestionID(ctx context.Context, userID string, questionID string) (count int64, err error)
GetIDsByUserIDAndQuestionID(ctx context.Context, userID string, questionID string) ([]int64, error)
SearchList(ctx context.Context, search *entity.AnswerSearch) ([]*entity.Answer, int64, error)
AdminSearchList(ctx context.Context, search *schema.AdminAnswerPageReq) ([]*entity.Answer, int64, error)
UpdateAnswerStatus(ctx context.Context, answerID string, status int) (err error)
Expand All @@ -60,12 +60,12 @@ func NewAnswerCommon(answerRepo AnswerRepo) *AnswerCommon {
}
}

func (as *AnswerCommon) SearchAnswered(ctx context.Context, userID, questionID string) (bool, error) {
count, err := as.answerRepo.GetCountByUserIDQuestionID(ctx, userID, questionID)
func (as *AnswerCommon) SearchAnswerIDs(ctx context.Context, userID, questionID string) ([]int64, error) {
ids, err := as.answerRepo.GetIDsByUserIDAndQuestionID(ctx, userID, questionID)
if err != nil {
return false, err
return nil, err
}
return count > 0, nil
return ids, nil
}

func (as *AnswerCommon) AdminSearchList(ctx context.Context, req *schema.AdminAnswerPageReq) (
Expand Down
4 changes: 2 additions & 2 deletions internal/service/answer_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,8 @@ func (as *AnswerService) Get(ctx context.Context, answerID, loginUserID string)
return info, questionInfo, has, nil
}

func (as *AnswerService) GetCountByUserIDQuestionID(ctx context.Context, userId string, questionId string) (answerCount int64, err error) {
return as.answerRepo.GetCountByUserIDQuestionID(ctx, userId, questionId)
func (as *AnswerService) GetCountByUserIDQuestionID(ctx context.Context, userId string, questionId string) (ids []int64, err error) {
return as.answerRepo.GetIDsByUserIDAndQuestionID(ctx, userId, questionId)
}

func (as *AnswerService) AdminSetAnswerStatus(ctx context.Context, req *schema.AdminUpdateAnswerStatusReq) error {
Expand Down
11 changes: 9 additions & 2 deletions internal/service/question_common/question.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"context"
"encoding/json"
"math"
"strconv"
"time"

"github.com/apache/incubator-answer/internal/base/constant"
Expand Down Expand Up @@ -297,11 +298,17 @@ func (qs *QuestionCommon) Info(ctx context.Context, questionID string, loginUser
isFollowed, _ := qs.followCommon.IsFollowed(ctx, loginUserID, questionID)
showinfo.IsFollowed = isFollowed

has, err = qs.AnswerCommon.SearchAnswered(ctx, loginUserID, dbinfo.ID)
ids, err := qs.AnswerCommon.SearchAnswerIDs(ctx, loginUserID, dbinfo.ID)
if err != nil {
log.Error("AnswerFunc.SearchAnswered", err)
}
showinfo.Answered = has
showinfo.Answered = len(ids) > 0

st := make([]string, 0)
for _, id := range ids {
st = append(st, strconv.FormatInt(id, 10))
}
showinfo.AnswerIDs = st

collectedMap, err := qs.collectionCommon.SearchObjectCollected(ctx, loginUserID, []string{dbinfo.ID})
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions ui/src/common/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ export interface QuestionDetailRes {
user_info: UserInfoBase;
answered: boolean;
collected: boolean;
answer_ids: string[];

[prop: string]: any;
}
Expand Down Expand Up @@ -396,6 +397,7 @@ export interface SiteSettings {
theme: AdminSettingsTheme;
site_seo: AdminSettingsSeo;
site_users: AdminSettingsUsers;
site_write: AdminSettingsWrite;
version: string;
revision: string;
}
Expand All @@ -415,6 +417,7 @@ export interface AdminSettingsLegal {
}

export interface AdminSettingsWrite {
restrict_answer?: boolean;
recommend_tags: string[];
required_tag: string;
reserved_tags: string[];
Expand Down
15 changes: 15 additions & 0 deletions ui/src/pages/Admin/Write/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
postRequireAndReservedTag,
} from '@/services';
import { handleFormError } from '@/utils';
import { writeSettingStore } from '@/stores';

const Index: FC = () => {
const { t } = useTranslation('translation', {
Expand All @@ -38,6 +39,11 @@ const Index: FC = () => {
const schema: JSONSchema = {
title: t('page_title'),
properties: {
restrict_answer: {
type: 'boolean',
title: t('restrict_answer.title'),
description: t('restrict_answer.text'),
},
recommend_tags: {
type: 'string',
title: t('recommend_tags.label'),
Expand All @@ -56,6 +62,12 @@ const Index: FC = () => {
},
};
const uiSchema: UISchema = {
restrict_answer: {
'ui:widget': 'switch',
'ui:options': {
label: t('required_tag.label'),
},
},
recommend_tags: {
'ui:widget': 'textarea',
'ui:options': {
Expand Down Expand Up @@ -92,13 +104,15 @@ const Index: FC = () => {
recommend_tags,
reserved_tags,
required_tag: formData.required_tag.value,
restrict_answer: formData.restrict_answer.value,
};
postRequireAndReservedTag(reqParams)
.then(() => {
Toast.onShow({
msg: t('update', { keyPrefix: 'toast' }),
variant: 'success',
});
writeSettingStore.getState().update(reqParams);
})
.catch((err) => {
if (err.isError) {
Expand All @@ -114,6 +128,7 @@ const Index: FC = () => {
formData.recommend_tags.value = res.recommend_tags.join('\n');
}
formData.required_tag.value = res.required_tag;
formData.restrict_answer.value = res.restrict_answer;
if (Array.isArray(res.reserved_tags)) {
formData.reserved_tags.value = res.reserved_tags.join('\n');
}
Expand Down
22 changes: 21 additions & 1 deletion ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { memo, useState, FC, useEffect } from 'react';
import { Form, Button, Alert } from 'react-bootstrap';
import { useTranslation, Trans } from 'react-i18next';
import { Link } from 'react-router-dom';

import { marked } from 'marked';
import classNames from 'classnames';
Expand All @@ -37,7 +38,9 @@ interface Props {
/** question id */
qid: string;
answered?: boolean;
restrictAnswer?: boolean;
loggedUserRank: number;
answer_ids?: string[];
};
callback?: (obj) => void;
}
Expand Down Expand Up @@ -195,6 +198,11 @@ const Index: FC<Props> = ({ visible = false, data, callback }) => {
if (!guard.tryNormalLogged(true)) {
return;
}
if (data?.answered && !showEditor && data?.restrictAnswer) {
setShowEditor(true);
return;
}

if (data?.answered && !showEditor) {
Modal.confirm({
title: t('confirm_title'),
Expand Down Expand Up @@ -223,6 +231,8 @@ const Index: FC<Props> = ({ visible = false, data, callback }) => {
setShowEditor(true);
setEditorFocusState(true);
};

console.log(data);
return (
<Form noValidate className="mt-4">
{(!data.answered || showEditor) && (
Expand Down Expand Up @@ -306,10 +316,20 @@ const Index: FC<Props> = ({ visible = false, data, callback }) => {
)}

{data.answered && !showEditor ? (
<Button onClick={clickBtn}>{t('add_another_answer')}</Button>
// the 0th answer is the oldest one
<Link to={`/posts/${data.qid}/${data.answer_ids?.at(0)}/edit`}>
<Button>{t('edit_answer')}</Button>
</Link>
) : (
<Button onClick={clickBtn}>{t('btn_name')}</Button>
)}

{data.answered && !showEditor && !data.restrictAnswer && (
<Button onClick={clickBtn} className="ms-2 " variant="outline-primary">
{t('add_another_answer')}
</Button>
)}

{hasDraft && (
<Button variant="link" className="ms-2" onClick={deleteDraft}>
{t('discard_draft', { keyPrefix: 'btns' })}
Expand Down
7 changes: 6 additions & 1 deletion ui/src/pages/Questions/Detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import { useTranslation } from 'react-i18next';

import { Pagination, CustomSidebar } from '@/components';
import { loggedUserInfoStore, toastStore } from '@/stores';
import { loggedUserInfoStore, toastStore, writeSettingStore } from '@/stores';
import { scrollToElementTop, scrollToDocTop } from '@/utils';
import { usePageTags, usePageUsers } from '@/hooks';
import type {
Expand Down Expand Up @@ -74,6 +74,7 @@ const Index = () => {
});
const { setUsers } = usePageUsers();
const userInfo = loggedUserInfoStore((state) => state.user);
const writeInfo = writeSettingStore((state) => state.write);
const isAuthor = userInfo?.username === question?.user_info?.username;
const isAdmin = userInfo?.role_id === 2;
const isModerator = userInfo?.role_id === 3;
Expand Down Expand Up @@ -229,6 +230,8 @@ const Index = () => {
}
}

console.log(question);

return (
<Row className="questionDetailPage pt-4 mb-5">
<Col className="page-main flex-auto">
Expand Down Expand Up @@ -279,7 +282,9 @@ const Index = () => {
data={{
qid,
answered: question?.answered,
restrictAnswer: writeInfo.restrict_answer,
loggedUserRank,
answer_ids: question?.answer_ids,
}}
callback={writeAnswerCallback}
/>
Expand Down
2 changes: 2 additions & 0 deletions ui/src/stores/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import brandingStore from './branding';
import pageTagStore from './pageTags';
import customizeStore from './customize';
import themeSettingStore from './themeSetting';
import writeSettingStore from './writeSetting';
import loginToContinueStore from './loginToContinue';
import errorCodeStore from './errorCode';
import sideNavStore from './sideNav';
Expand All @@ -49,4 +50,5 @@ export {
userCenterStore,
sideNavStore,
commentReplyStore,
writeSettingStore,
};
Loading

0 comments on commit b840399

Please sign in to comment.