1 /**
2 * Copyright © The Bot Blog 2019
3 * License: MIT (https://github.com/TheBotBlog/thebotbloglib/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module thebotbloglib.facebookcomment;
7 
8 import std.string : strip, toLower;
9 import std.array : split;
10 import std.algorithm : count;
11 
12 import thebotbloglib.webmanager;
13 import thebotbloglib.facebookservice;
14 import thebotbloglib.graphapi;
15 import thebotbloglib.facebookreact;
16 
17 /// A Facebook comment.
18 final class FacebookComment
19 {
20   private:
21   /// The facebook service.
22   FacebookService _service;
23   /// The comment id.
24   string _commentId;
25   /// The id.
26   string _id;
27   /// The time the comment was created.
28   string _createdTime;
29   /// The comment's message.
30   string _message;
31   /// The author's name.
32   string _authorName;
33   /// The author's id.
34   string _authorId;
35 
36   /// All the like reactions.
37   FacebookReact[] _likeReacts;
38   /// All the love reactions.
39   FacebookReact[] _loveReacts;
40   /// All the wow reactions.
41   FacebookReact[] _wowReacts;
42   /// All the haha reactions.
43   FacebookReact[] _hahaReacts;
44   /// All the sad reactions.
45   FacebookReact[] _sadReacts;
46   /// All the angry reactions.
47   FacebookReact[] _angryReacts;
48 
49   /// The total amount of reactions.
50   size_t _totalReacts;
51   /// The total amount of positive reactions.
52   size_t _totalPositiveReacts;
53   /// The total amount of inclusive positive reactions.
54   size_t _totalInclusivePositiveReacts;
55   /// The total amount of negative reactions.
56   size_t _totalNegativeReacts;
57   /// The total reaction rate.
58   ptrdiff_t _totalReactionRate;
59 
60   package(thebotbloglib)
61   {
62     final:
63     /**
64     * Creates a new Facebook comment.
65     * Params:
66     *   service = The Facebook service to associate the comment with.
67     */
68     this(FacebookService service)
69     {
70       _service = service;
71     }
72 
73     @property
74     {
75       /// Sets the id of the comment.
76       void id(string newId)
77       {
78         _id = newId;
79       }
80 
81       /// Sets the created time of the comment.
82       void createdTime(string newCreatedTime)
83       {
84         _createdTime = newCreatedTime;
85       }
86 
87       /// Sets the message of the comment.
88       void message(string newMessage)
89       {
90         _message = newMessage;
91       }
92 
93       /// Sets the author's name.
94       void authorName(string newAuthorName)
95       {
96         _authorName = newAuthorName;
97       }
98 
99       /// Sets the author's id.
100       void authorId(string authorId)
101       {
102         _authorId = authorId;
103       }
104     }
105   }
106 
107   public:
108   final:
109   @property
110   {
111     /// Gets the id.
112     string id() { return _id; }
113 
114     /// Gets the time the comment was created.
115     string createdTime() { return _createdTime; }
116 
117     /// Gets the message.
118     string message() { return _message; }
119 
120     /// Gets the author's name.
121     string authorName() { return _authorName; }
122 
123     /// Gets the author's id.
124     string authorId() { return _authorId; }
125 
126     /// Gets the comment id.
127     string commentId()
128     {
129       if (id && id.strip.length && (!_commentId || !_commentId.strip.length))
130       {
131         auto idData = id.split("_");
132 
133         if (idData.length > 1)
134         {
135           _commentId = idData[1];
136         }
137       }
138 
139       return _commentId;
140     }
141 
142     /// Gets the like reactions.
143     FacebookReact[] likeReacts() { return _likeReacts; }
144 
145     /// Gets the love reactions.
146     FacebookReact[] loveReacts() { return _loveReacts; }
147 
148     /// Gets the wow reactions.
149     FacebookReact[] wowReacts() { return _wowReacts; }
150 
151     /// Gets the haha reactions.
152     FacebookReact[] hahaReacts() { return _hahaReacts; }
153 
154     /// Gets sad reactions.
155     FacebookReact[] sadReacts() { return _sadReacts; }
156 
157     /// Gets the angry reactions.
158     FacebookReact[] angryReacts() { return _angryReacts; }
159 
160     /// Gets the total reactions.
161     size_t totalReacts() { return _totalReacts; }
162 
163     /// Gets the total positive reactions.
164     size_t totalPositiveReacts() { return _totalPositiveReacts; }
165 
166     /// Gets the total inclusive positive reactions.
167     size_t totalInclusivePositiveReacts() { return _totalInclusivePositiveReacts; }
168 
169     /// Gets the total negative reactions.
170     size_t totalNegativeReacts() { return _totalNegativeReacts; }
171 
172     /// Gets the totoal reaction rate.
173     ptrdiff_t totalReactionRate() { return _totalReactionRate; }
174   }
175 
176   /// Updates the reaactions.
177   void updateReacts()
178   {
179     FacebookReact[] reacts = [];
180 
181     auto web = new WebManager(_service);
182 
183     string[string] data;
184 
185     auto resp = web.getRequest!GraphAPIObjectReactions(id, "reactions", data);
186 
187     auto nextUrl = fillReacts(resp, reacts);
188 
189     while (nextUrl && nextUrl.strip.length)
190     {
191       resp = web.getRequestRaw!GraphAPIObjectReactions(nextUrl);
192 
193       nextUrl = fillReacts(resp, reacts);
194     }
195 
196     _totalReacts = reacts.count!(r => r.reactionType != "none");
197 
198     _likeReacts = [];
199     _loveReacts = [];
200     _wowReacts = [];
201     _hahaReacts = [];
202     _sadReacts = [];
203     _angryReacts = [];
204 
205     foreach (react; reacts)
206     {
207       switch (react.reactionType)
208       {
209         case "like": _likeReacts ~= react; break;
210         case "love": _loveReacts ~= react; break;
211         case "wow": _wowReacts ~= react; break;
212         case "haha": _hahaReacts ~= react; break;
213         case "sad": _sadReacts ~= react; break;
214         case "angry": _angryReacts ~= react; break;
215 
216         default: break;
217       }
218     }
219 
220     _totalPositiveReacts = (_likeReacts.length + _loveReacts.length);
221     _totalInclusivePositiveReacts = (_totalPositiveReacts + _hahaReacts.length);
222     _totalNegativeReacts = (_sadReacts.length + _angryReacts.length);
223 
224     _totalReactionRate = _totalPositiveReacts - _angryReacts.length;
225   }
226 
227   /**
228   * Fills the reactions.
229   * Params:
230   *   resp = The graph api response.
231   *   reacts = (ref) The reaction collection to append to.
232   */
233   private string fillReacts(GraphAPIObjectReactions resp, ref FacebookReact[] reacts)
234   {
235     if (resp && resp.data && resp.data.length)
236     {
237       foreach (data; resp.data)
238       {
239         auto react = new FacebookReact;
240         react.id = data.id;
241         react.name = data.name;
242         react.reactionType = data.type.toLower.strip;
243 
244         reacts ~= react;
245       }
246 
247       if (resp.paging && resp.paging.next && resp.paging.next.strip.length)
248       {
249         return resp.paging.next;
250       }
251     }
252 
253     return null;
254   }
255 }