Huggle  build:^490^dce1e5c
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
hugglefeedproviderwiki.cpp
1 //This program is free software: you can redistribute it and/or modify
2 //it under the terms of the GNU General Public License as published by
3 //the Free Software Foundation, either version 3 of the License, or
4 //(at your option) any later version.
5 
6 //This program is distributed in the hope that it will be useful,
7 //but WITHOUT ANY WARRANTY; without even the implied warranty of
8 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 //GNU General Public License for more details.
10 
11 #include "hugglefeedproviderwiki.hpp"
12 
13 using namespace Huggle;
14 
15 HuggleFeedProviderWiki::HuggleFeedProviderWiki()
16 {
17  Buffer = new QList<WikiEdit*>();
18  Refreshing = false;
19  q = NULL;
20  // we set the latest time to yesterday so that we don't get in troubles with time offset
21  LatestTime = QDateTime::currentDateTime().addDays(-1);
22  LastRefresh = QDateTime::currentDateTime().addDays(-1);
23 }
24 
25 HuggleFeedProviderWiki::~HuggleFeedProviderWiki()
26 {
27  while (Buffer->count() > 0)
28  {
29  Buffer->at(0)->UnregisterConsumer(HUGGLECONSUMER_WIKIEDIT);
30  Buffer->removeAt(0);
31  }
32  delete Buffer;
33  if (q != NULL)
34  {
35  if (!q->IsManaged())
36  {
37  delete q;
38  }
39  }
40 }
41 
43 {
44  this->Resume();
45  Refresh();
46  return true;
47 }
48 
50 {
51  return true;
52 }
53 
55 {
56  this->Pause();
57 }
58 
60 {
61  if (this->Buffer->size() == 0)
62  {
63  if (this->LastRefresh.addSecs(6) < QDateTime::currentDateTime())
64  {
65  Refresh();
66  this->LastRefresh = QDateTime::currentDateTime();
67  }
68  return false;
69  }
70  return true;
71 }
72 
74 {
75  if (Refreshing)
76  {
77  // the query is still in progress now
78  if (!q->Processed())
79  {
80  return;
81  }
82  if (q->Result->Failed)
83  {
84  // failed to obtain the data
85  /// \todo LOCALIZE ME
86  Core::Log("Unable to retrieve data from wiki feed, last error: " + q->Result->ErrorMessage);
87  q->UnregisterConsumer("HuggleFeed::Refresh");
88  this->q = NULL;
89  Refreshing = false;
90  return;
91  }
92  this->Process(q->Result->Data);
93  q->UnregisterConsumer("HuggleFeed::Refresh");
94  this->q = NULL;
95  Refreshing = false;
96  return;
97  }
98 
99  Refreshing = true;
100  q = new ApiQuery();
101  q->SetAction(ActionQuery);
102  q->Parameters = "list=recentchanges&rcprop=" + QUrl::toPercentEncoding("user|userid|comment|flags|timestamp|title|ids|sizes") +
103  "&rcshow=" + QUrl::toPercentEncoding("!bot") + "&rclimit=200";
104  q->Target = "Recent changes refresh";
105  q->RegisterConsumer("HuggleFeed::Refresh");
107  q->Process();
108 }
109 
111 {
112  if (this->Buffer->size() < 1)
113  {
114  return NULL;
115  }
116  WikiEdit *edit = this->Buffer->at(0);
117  this->Buffer->removeAt(0);
118  Core::PostProcessEdit(edit);
119  return edit;
120 }
121 
122 void HuggleFeedProviderWiki::Process(QString data)
123 {
124  //QStringList lines = data.split("\n");
125  QDomDocument d;
126  d.setContent(data);
127  QDomNodeList l = d.elementsByTagName("rc");
128  int CurrentNode = l.count();
129  if (l.count() == 0)
130  {
131  Core::Log("Error, wiki provider returned: " + data);
132  return;
133  }
134  // recursively scan all RC changes
135  QDateTime t = this->LatestTime;
136  bool Changed = false;
137  while (CurrentNode > 0)
138  {
139  CurrentNode--;
140  // get a time of rc change
141  QDomElement item = l.at(CurrentNode).toElement();
142 
143  if (item.nodeName() != "rc")
144  {
145  CurrentNode--;
146  continue;
147  }
148 
149  if (!item.attributes().contains("timestamp"))
150  {
151  Core::Log("RC Feed: Item was missing timestamp attribute: " + item.toElement().nodeName());
152  CurrentNode--;
153  continue;
154  }
155 
156  QDateTime time = QDateTime::fromString(item.attribute("timestamp"), "yyyy-MM-ddThh:mm:ssZ");
157 
158  if (time < t)
159  {
160  // this record is older than latest parsed record, so we don't want to parse it
161  CurrentNode--;
162  continue;
163  } else
164  {
165  Changed = true;
166  t = time;
167  }
168 
169  if (!item.attributes().contains("type"))
170  {
171  Core::Log("RC Feed: Item was missing type attribute: " + item.text());
172  CurrentNode--;
173  continue;
174  }
175 
176  QString type = item.attribute("type");
177 
178  if (type != "edit" && type != "new")
179  {
180  CurrentNode--;
181  continue;
182  }
183 
184  if (!item.attributes().contains("title"))
185  {
186  Core::Log("RC Feed: Item was missing title attribute: " + item.text());
187  CurrentNode--;
188  continue;
189  }
190 
191  WikiEdit *edit = new WikiEdit();
192  edit->Page = new WikiPage(item.attribute("title"));
193 
194  if (type == "new")
195  {
196  edit->NewPage = true;
197  }
198 
199  if (item.attributes().contains("newlen") && item.attributes().contains("oldlen"))
200  {
201  edit->Size = item.attribute("newlen").toInt() - item.attribute("oldlen").toInt();
202  }
203 
204  if (item.attributes().contains("user"))
205  {
206  edit->User = new WikiUser(item.attribute("user"));
207  }
208 
209  if (item.attributes().contains("comment"))
210  {
211  edit->Summary = item.attribute("comment");
212  }
213 
214  if (item.attributes().contains("bot"))
215  {
216  edit->Bot = true;
217  }
218 
219  if (item.attributes().contains("anon"))
220  {
221  edit->User->ForceIP();
222  }
223 
224  if (item.attributes().contains("revid"))
225  {
226  edit->RevID = QString(item.attribute("revid")).toInt();
227  if (edit->RevID == 0)
228  {
229  edit->RevID = -1;
230  }
231  }
232 
233  if (item.attributes().contains("minor"))
234  {
235  edit->Minor = true;
236  }
237 
238  this->InsertEdit(edit);
239 
240  CurrentNode--;
241  }
242  if (Changed)
243  {
244  this->LatestTime = t.addSecs(1);
245  }
246 }
247 
248 void HuggleFeedProviderWiki::InsertEdit(WikiEdit *edit)
249 {
251  Core::PreProcessEdit(edit);
252  if (Core::Main->Queue1->CurrentFilter->Matches(edit))
253  {
254  if (this->Buffer->size() > Configuration::ProviderCache)
255  {
256  while (this->Buffer->size() > (Configuration::ProviderCache - 10))
257  {
258  this->Buffer->at(0)->UnregisterConsumer(HUGGLECONSUMER_WIKIEDIT);
259  this->Buffer->removeAt(0);
260  }
261  Core::Log("WARNING: insufficient space in irc cache, increase ProviderCache size, otherwise you will be loosing edits");
262  }
263  this->Buffer->append(edit);
264  } else
265  {
266  edit->UnregisterConsumer(HUGGLECONSUMER_WIKIEDIT);
267  }
268 }
bool IsManaged()
IsManaged Managed class is deleted by GC and must not be deleted by hand.
bool Start()
Start the feed engine.
static void Log(QString Message)
Write text to terminal as well as ring log.
Definition: core.cpp:563
bool NewPage
Edit is a new page.
Definition: wikiedit.hpp:95
QString Target
This is optional property which contains a label of target this query is for.
Definition: apiquery.hpp:98
int RevID
Revision ID.
Definition: wikiedit.hpp:105
static void PostProcessEdit(WikiEdit *_e)
Definition: core.cpp:774
virtual bool Processed()
Returns true in case that query is processed.
Definition: query.cpp:45
void UnregisterConsumer(const int consumer)
This function will remove a string which prevent the object from being removed.
Definition: collectable.cpp:68
void Stop()
Stop the feed engine.
void RegisterConsumer(const int consumer)
Registers a consumer.
Definition: collectable.cpp:57
static void AppendQuery(Query *item)
Insert a query to internal list of running queries, so that they can be watched This will insert it t...
Definition: core.cpp:557
void Process()
Run.
Definition: apiquery.cpp:138
static double EditCounter
Number of edits made since you logged in.
Mediawiki page.
Definition: wikipage.hpp:43
QString Summary
Summary of edit.
Definition: wikiedit.hpp:110
static void PreProcessEdit(WikiEdit *_e)
Definition: core.cpp:747
static int ProviderCache
Size of feed.
void SetAction(const Action action)
Change the action type.
Definition: apiquery.cpp:185
bool Minor
Edit is a minor edit.
Definition: wikiedit.hpp:91
virtual void Resume()
Resume edit parsing.
Definition: hugglefeed.hpp:38
bool IsWorking()
Return true if this feed is operational or not.
WikiUser * User
User who changed the page.
Definition: wikiedit.hpp:89
bool ContainsEdit()
Check if feed is containing some edits in buffer.
QString ErrorMessage
If query is in error the reason for error is stored here.
Definition: queryresult.hpp:27
QString Parameters
Parameters for action, for example page title.
Definition: apiquery.hpp:84
int Size
Size of change of edit.
Definition: wikiedit.hpp:97
void ForceIP()
Change the IP property to true forcefully even if user isn&#39;t IP.
Definition: wikiuser.cpp:235
Wiki edit.
Definition: wikiedit.hpp:67
static MainWindow * Main
Pointer to main.
Definition: core.hpp:111
This class can be used to execute any kind of api query on any wiki.
Definition: apiquery.hpp:55
WikiEdit * RetrieveEdit()
Return a last edit from cache or NULL.
bool Bot
Edit is a bot edit.
Definition: wikiedit.hpp:93
WikiPage * Page
Page that was changed by edit.
Definition: wikiedit.hpp:87
QString Data
Data retrieved by query.
Definition: queryresult.hpp:25
QueryResult * Result
Result of query, see documentation of QueryResult for more.
Definition: query.hpp:68
virtual void Pause()
This is useful to stop parsing edits from irc and like in case that queue is full.
Definition: hugglefeed.hpp:36