2018-11-18 11:00:15 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module BitbucketServer
|
|
|
|
module Representation
|
|
|
|
# A general comment with the structure:
|
|
|
|
# "comment": {
|
|
|
|
# "author": {
|
|
|
|
# "active": true,
|
|
|
|
# "displayName": "root",
|
|
|
|
# "emailAddress": "stanhu+bitbucket@gitlab.com",
|
|
|
|
# "id": 1,
|
|
|
|
# "links": {
|
|
|
|
# "self": [
|
|
|
|
# {
|
|
|
|
# "href": "http://localhost:7990/users/root"
|
|
|
|
# }
|
|
|
|
# ]
|
|
|
|
# },
|
|
|
|
# "name": "root",
|
|
|
|
# "slug": "root",
|
|
|
|
# "type": "NORMAL"
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
class Comment < Representation::Base
|
|
|
|
attr_reader :parent_comment
|
|
|
|
|
|
|
|
CommentNode = Struct.new(:raw_comments, :parent)
|
|
|
|
|
|
|
|
def initialize(raw, parent_comment: nil)
|
|
|
|
super(raw)
|
|
|
|
|
|
|
|
@parent_comment = parent_comment
|
|
|
|
end
|
|
|
|
|
|
|
|
def id
|
|
|
|
raw_comment['id']
|
|
|
|
end
|
|
|
|
|
|
|
|
def author_username
|
2020-11-24 15:15:51 +05:30
|
|
|
author['username'] ||
|
|
|
|
author['slug'] ||
|
|
|
|
author['displayName']
|
2018-11-18 11:00:15 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def author_email
|
|
|
|
author['emailAddress']
|
|
|
|
end
|
|
|
|
|
|
|
|
def note
|
|
|
|
raw_comment['text']
|
|
|
|
end
|
|
|
|
|
|
|
|
def created_at
|
|
|
|
self.class.convert_timestamp(created_date)
|
|
|
|
end
|
|
|
|
|
|
|
|
def updated_at
|
|
|
|
self.class.convert_timestamp(created_date)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Bitbucket Server supports the ability to reply to any comment
|
|
|
|
# and created multiple threads. It represents these as a linked list
|
|
|
|
# of comments within comments. For example:
|
|
|
|
#
|
|
|
|
# "comments": [
|
|
|
|
# {
|
|
|
|
# "author" : ...
|
|
|
|
# "comments": [
|
|
|
|
# {
|
|
|
|
# "author": ...
|
|
|
|
#
|
|
|
|
# Since GitLab only supports a single thread, we flatten all these
|
|
|
|
# comments into a single discussion.
|
|
|
|
def comments
|
|
|
|
@comments ||= flatten_comments
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
# In order to provide context for each reply, we need to track
|
|
|
|
# the parent of each comment. This method works as follows:
|
|
|
|
#
|
|
|
|
# 1. Insert the root comment into the workset. The root element is the current note.
|
|
|
|
# 2. For each node in the workset:
|
|
|
|
# a. Examine if it has replies to that comment. If it does,
|
|
|
|
# insert that node into the workset.
|
|
|
|
# b. Parse that note into a Comment structure and add it to a flat list.
|
|
|
|
def flatten_comments
|
|
|
|
comments = raw_comment['comments']
|
|
|
|
workset =
|
|
|
|
if comments
|
|
|
|
[CommentNode.new(comments, self)]
|
|
|
|
else
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
|
|
|
|
all_comments = []
|
|
|
|
|
|
|
|
until workset.empty?
|
|
|
|
node = workset.pop
|
|
|
|
parent = node.parent
|
|
|
|
|
|
|
|
node.raw_comments.each do |comment|
|
|
|
|
new_comments = comment.delete('comments')
|
|
|
|
current_comment = Comment.new({ 'comment' => comment }, parent_comment: parent)
|
|
|
|
all_comments << current_comment
|
|
|
|
workset << CommentNode.new(new_comments, current_comment) if new_comments
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
all_comments
|
|
|
|
end
|
|
|
|
|
|
|
|
def raw_comment
|
|
|
|
raw.fetch('comment', {})
|
|
|
|
end
|
|
|
|
|
|
|
|
def author
|
|
|
|
raw_comment['author']
|
|
|
|
end
|
|
|
|
|
|
|
|
def created_date
|
|
|
|
raw_comment['createdDate']
|
|
|
|
end
|
|
|
|
|
|
|
|
def updated_date
|
|
|
|
raw_comment['updatedDate']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|