github.com/Ptt-official-app/go-bbs@v0.12.0/user_comment_record.go (about)

     1  package bbs
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  	"time"
     8  )
     9  
    10  var (
    11  	ErrNotUserComment          = fmt.Errorf("data is not a user comment")
    12  	ErrUserCommentEmptyUserID  = fmt.Errorf("user comment has empty name")
    13  	ErrUserCommentEmptyComment = fmt.Errorf("user comment detail has empty")
    14  )
    15  
    16  var (
    17  	userCommentPattern = regexp.MustCompile(`([a-zA-Z][a-zA-Z0-9]+):.*([0-9][0-9]\/[0-9][0-9]\s[0-9][0-9]:[0-9][0-9])`)
    18  )
    19  
    20  type UserCommentRecord interface {
    21  	CommentOrder() uint32
    22  	CommentTime() time.Time
    23  	Owner() string
    24  	IP() string
    25  	Comment() string
    26  	String() string
    27  	BoardID() string
    28  	Filename() string
    29  }
    30  
    31  var _ UserCommentRecord = &userCommentRecord{}
    32  
    33  type userCommentRecord struct {
    34  	commentOrder uint32
    35  	commentTime  time.Time
    36  	owner        string
    37  	ip           string
    38  	boardID      string
    39  	filename     string
    40  	comment      string
    41  }
    42  
    43  // NewUserCommentRecord parses the data and returns the user comment record.
    44  //  Return error when input data is not matched the user comment pattern.
    45  func NewUserCommentRecord(order uint32, data string, boardID string, ar ArticleRecord) (UserCommentRecord, error) {
    46  	owner, ctime, comment, err := parseUserComment(data)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	return &userCommentRecord{
    51  		commentOrder: order,
    52  		commentTime:  ctime,
    53  		owner:        owner,
    54  		ip:           "", // TODO
    55  		boardID:      boardID,
    56  		filename:     ar.Filename(),
    57  		comment:      comment,
    58  	}, nil
    59  }
    60  
    61  func (r userCommentRecord) CommentOrder() uint32 {
    62  	return r.commentOrder
    63  }
    64  
    65  func (r userCommentRecord) CommentTime() time.Time {
    66  	return r.commentTime
    67  }
    68  
    69  func (r userCommentRecord) Owner() string {
    70  	return r.owner
    71  }
    72  
    73  func (r userCommentRecord) IP() string {
    74  	return r.ip
    75  }
    76  
    77  func (r userCommentRecord) Comment() string {
    78  	return r.comment
    79  }
    80  
    81  func (r userCommentRecord) String() string {
    82  	return fmt.Sprintf("order: %d, owner: %s, time: %s", r.commentOrder, r.owner, r.commentTime.Format("01/02 15:04"))
    83  }
    84  
    85  func (r userCommentRecord) BoardID() string {
    86  	return r.boardID
    87  }
    88  
    89  func (r userCommentRecord) Filename() string {
    90  	return r.filename
    91  }
    92  
    93  // parseUserComment returns the owner and time of comment data.
    94  //  Return ErrNotUserComment error when data doesn't match to the pattern.
    95  //  Return other error when data contains the ambiguous value which can't parse.
    96  func parseUserComment(data string) (owner string, ctime time.Time, comment string, err error) {
    97  	matches := userCommentPattern.FindStringSubmatch(data)
    98  	// The 1st record is entire matched result of row.
    99  	// The 2nd record is group owner result, EX: "pichu".
   100  	const ownerIdx = 1
   101  	// The 3rd record is group time result,  EX: "05/15 01:06".
   102  	const timeIdx = 2
   103  
   104  	const commentIdx = 0
   105  
   106  	if len(matches) < 3 {
   107  		err = ErrNotUserComment
   108  		return
   109  	}
   110  
   111  	owner = matches[ownerIdx]
   112  	if len(owner) == 0 {
   113  		err = ErrUserCommentEmptyUserID
   114  		return
   115  	}
   116  
   117  	ctimeStr := matches[timeIdx]
   118  	ctime, err = time.Parse("01/02 15:04", ctimeStr)
   119  	if err != nil {
   120  		return
   121  	}
   122  
   123  	commentStr := matches[commentIdx]
   124  	if len(commentStr) == 0 {
   125  		err = ErrUserCommentEmptyComment
   126  		return
   127  	}
   128  
   129  	//TODO: improve get comment
   130  	ownStr := ":"
   131  	commentTimeRemoveArr := strings.Split(commentStr, ctimeStr)
   132  	commentArr := strings.Split(commentTimeRemoveArr[0], ownStr)
   133  
   134  	for key, value := range commentArr {
   135  		//key 0 為使用者名稱,跳過
   136  		if key == 0 {
   137  			continue
   138  		}
   139  		comment += strings.TrimSpace(value)
   140  		//key 2 開始才會有重複冒號的問題
   141  		if key >= 2 {
   142  			comment += ":"
   143  		}
   144  	}
   145  
   146  	return owner, ctime, comment, nil
   147  }