/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package report import ( "context" "encoding/json" "github.com/apache/answer/internal/service/eventqueue" "github.com/apache/answer/internal/base/constant" "github.com/apache/answer/internal/base/handler" "github.com/apache/answer/internal/base/pager" "github.com/apache/answer/internal/base/reason" "github.com/apache/answer/internal/entity" "github.com/apache/answer/internal/schema" answercommon "github.com/apache/answer/internal/service/answer_common" "github.com/apache/answer/internal/service/comment_common" "github.com/apache/answer/internal/service/config" "github.com/apache/answer/internal/service/object_info" questioncommon "github.com/apache/answer/internal/service/question_common" "github.com/apache/answer/internal/service/report_common" "github.com/apache/answer/internal/service/report_handle" usercommon "github.com/apache/answer/internal/service/user_common" "github.com/apache/answer/pkg/checker" "github.com/apache/answer/pkg/htmltext" "github.com/apache/answer/pkg/obj" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) // ReportService user service type ReportService struct { reportRepo report_common.ReportRepo objectInfoService *object_info.ObjService commonUser *usercommon.UserCommon answerRepo answercommon.AnswerRepo questionRepo questioncommon.QuestionRepo commentCommonRepo comment_common.CommentCommonRepo reportHandle *report_handle.ReportHandle configService *config.ConfigService eventQueueService eventqueue.Service } // NewReportService new report service func NewReportService( reportRepo report_common.ReportRepo, objectInfoService *object_info.ObjService, commonUser *usercommon.UserCommon, answerRepo answercommon.AnswerRepo, questionRepo questioncommon.QuestionRepo, commentCommonRepo comment_common.CommentCommonRepo, reportHandle *report_handle.ReportHandle, configService *config.ConfigService, eventQueueService eventqueue.Service, ) *ReportService { return &ReportService{ reportRepo: reportRepo, objectInfoService: objectInfoService, commonUser: commonUser, answerRepo: answerRepo, questionRepo: questionRepo, commentCommonRepo: commentCommonRepo, reportHandle: reportHandle, configService: configService, eventQueueService: eventQueueService, } } // AddReport add report func (rs *ReportService) AddReport(ctx context.Context, req *schema.AddReportReq) (err error) { objectTypeNumber, err := obj.GetObjectTypeNumberByObjectID(req.ObjectID) if err != nil { return err } objInfo, err := rs.objectInfoService.GetInfo(ctx, req.ObjectID) if err != nil { return err } if objInfo.IsDeleted() { return errors.BadRequest(reason.NewObjectAlreadyDeleted) } cf, err := rs.configService.GetConfigByID(ctx, req.ReportType) if err != nil || cf == nil { return errors.BadRequest(reason.ReportNotFound) } if cf.Key == constant.ReasonADuplicate && !checker.IsURL(req.Content) { return errors.BadRequest(reason.InvalidURLError) } report := &entity.Report{ UserID: req.UserID, ReportedUserID: objInfo.ObjectCreatorUserID, ObjectID: req.ObjectID, ObjectType: objectTypeNumber, ReportType: req.ReportType, Content: req.Content, Status: entity.ReportStatusPending, } err = rs.reportRepo.AddReport(ctx, report) if err != nil { return err } rs.sendEvent(ctx, report, objInfo) return nil } // GetUnreviewedReportPostPage get unreviewed report post page func (rs *ReportService) GetUnreviewedReportPostPage(ctx context.Context, req *schema.GetUnreviewedReportPostPageReq) ( pageModel *pager.PageModel, err error) { if !req.IsAdmin { return pager.NewPageModel(0, make([]*schema.GetReportListPageResp, 0)), nil } lang := handler.GetLangByCtx(ctx) reports, total, err := rs.reportRepo.GetReportListPage(ctx, &schema.GetReportListPageDTO{ Page: req.Page, PageSize: 1, Status: entity.ReportStatusPending, }) if err != nil { return } resp := make([]*schema.GetReportListPageResp, 0) for _, report := range reports { info, err := rs.objectInfoService.GetUnreviewedRevisionInfo(ctx, report.ObjectID) if err != nil { log.Errorf("GetUnreviewedRevisionInfo failed, err: %v", err) continue } r := &schema.GetReportListPageResp{ FlagID: report.ID, CreatedAt: info.CreatedAt, ObjectID: info.ObjectID, ObjectType: info.ObjectType, QuestionID: info.QuestionID, AnswerID: info.AnswerID, CommentID: info.CommentID, Title: info.Title, UrlTitle: htmltext.UrlTitle(info.Title), OriginalText: info.Content, ParsedText: info.Html, AnswerCount: info.AnswerCount, AnswerAccepted: info.AnswerAccepted, Tags: info.Tags, SubmitAt: report.CreatedAt.Unix(), ObjectStatus: info.Status, ObjectShowStatus: info.ShowStatus, ReasonContent: report.Content, } // get user info userInfo, exists, e := rs.commonUser.GetUserBasicInfoByID(ctx, info.ObjectCreatorUserID) if e != nil { log.Errorf("user not found by id: %s, err: %v", info.ObjectCreatorUserID, e) } if exists { _ = copier.Copy(&r.AuthorUserInfo, userInfo) } // get submitter info submitter, exists, e := rs.commonUser.GetUserBasicInfoByID(ctx, report.ReportedUserID) if e != nil { log.Errorf("user not found by id: %s, err: %v", info.ObjectCreatorUserID, e) } if exists { _ = copier.Copy(&r.SubmitterUser, submitter) } if report.ReportType > 0 { r.Reason = &schema.ReasonItem{ReasonType: report.ReportType} cf, err := rs.configService.GetConfigByID(ctx, report.ReportType) if err != nil { log.Error(err) } else { _ = json.Unmarshal([]byte(cf.Value), r.Reason) r.Reason.Translate(cf.Key, lang) } } resp = append(resp, r) } return pager.NewPageModel(total, resp), nil } // ReviewReport review report func (rs *ReportService) ReviewReport(ctx context.Context, req *schema.ReviewReportReq) (err error) { report, exist, err := rs.reportRepo.GetByID(ctx, req.FlagID) if err != nil { return err } if !exist { return errors.NotFound(reason.ReportNotFound) } // check if handle or not if report.Status != entity.ReportStatusPending { return nil } // ignore this report if req.OperationType == constant.ReportOperationIgnoreReport { return rs.reportRepo.UpdateStatus(ctx, report.ID, entity.ReportStatusIgnore) } if err = rs.reportHandle.UpdateReportedObject(ctx, report, req); err != nil { return } return rs.reportRepo.UpdateStatus(ctx, report.ID, entity.ReportStatusCompleted) } func (rs *ReportService) sendEvent(ctx context.Context, report *entity.Report, objectInfo *schema.SimpleObjectInfo) { var event *schema.EventMsg switch objectInfo.ObjectType { case constant.QuestionObjectType: event = schema.NewEvent(constant.EventQuestionFlag, report.UserID).TID(objectInfo.QuestionID). QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID) case constant.AnswerObjectType: event = schema.NewEvent(constant.EventAnswerFlag, report.UserID).TID(objectInfo.AnswerID). AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID) case constant.CommentObjectType: event = schema.NewEvent(constant.EventCommentFlag, report.UserID).TID(objectInfo.CommentID). CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID) default: return } rs.eventQueueService.Send(ctx, event) }