Coverage for src/pyrsslocal/rss/rss_blogpost.py: 84%

111 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2023-02-02 02:59 +0100

1""" 

2@file 

3@brief description of a blog post 

4""" 

5import datetime 

6from textwrap import dedent 

7import jinja2 

8from pyquickhelper.loghelper.convert_helper import str2datetime 

9 

10 

11class BlogPost: 

12 

13 """ 

14 A blog post. 

15 

16 :: 

17 

18 <item> 

19 <title>Raw food</title> 

20 <link>http://www.xavierdupre.fr/blog/xd_blog.html?date=2013-06-30</link> 

21 <guid isPermaLink="true">http://www.xavierdupre.fr/blog/xd_blog.html?date=2013-06-30</guid> 

22 <description>&lt;p&gt; J'ecoutais une em....</description> 

23 <pubDate>2013-06-30 00:00:00</pubDate> 

24 </item> 

25 

26 @var id_rss id of the blog source 

27 @var title title of the stream 

28 @var guid guid 

29 @var isPermaLink isPermaLink 

30 @var link url of the blog post 

31 @var description description 

32 @var pubDate pubDate 

33 @var keywords list of keywords 

34 @var status status (dictionary with variables) 

35 """ 

36 

37 def __init__(self, id_rss, title, guid, isPermaLink, link, # pylint: disable=W0622 

38 description, pubDate, keywords=None, id=-1): # pylint: disable=W0622 

39 """ 

40 @param id_rss id of rss or @see cl Stream class 

41 @param title title of the stream 

42 @param guid guid 

43 @param isPermaLink isPermaLink 

44 @param link url of the blog post 

45 @param description description 

46 @param pubDate pubDate 

47 @param keywords keywords 

48 @param id blog id 

49 """ 

50 if keywords is None: 

51 keywords = [] 

52 self.id_rss = id_rss 

53 self.title = title 

54 self.guid = guid 

55 self.isPermaLink = isPermaLink 

56 self.link = link 

57 self.description = description 

58 self.pubDate = pubDate 

59 self.keywords = keywords 

60 self.id = id 

61 self.status = None 

62 self.statusList = [ 

63 "jokes", "programming", "data", "reject", 

64 "read", "keep", "interesting", 

65 "teachings", "work"] 

66 

67 if self.id_rss is None: 

68 raise Exception("no source (StreamRSS) for this post") 

69 if isinstance(self.id_rss, int): 

70 if self.id_rss == -1: 

71 raise ValueError( 

72 "the source id (self.id_rss) is equal to -1, not allowed") 

73 elif self.id_rss.id == -1: 

74 raise ValueError( 

75 "the source id (self.id_rss.id) is equal to -1, not allowed") 

76 

77 if isinstance(self.pubDate, str): 

78 self.pubDate = str2datetime(self.pubDate) 

79 

80 def add_status(self, status): 

81 """ 

82 Attaches a dictionary representing the status. 

83 

84 @param status dictionary 

85 """ 

86 self.status = status 

87 

88 def __str__(self): 

89 """ 

90 usual 

91 """ 

92 return "%s: %s (from %s)" % ( 

93 str(self.pubDate), self.title, self.id_rss) 

94 

95 @property 

96 def index(self): 

97 """ 

98 Defines the column to use as an index. 

99 """ 

100 return "guid" 

101 

102 @property 

103 def indexes(self): 

104 """ 

105 Defines other indexes to create. 

106 """ 

107 return ["id_rss"] 

108 

109 @property 

110 def asdict(self): 

111 """ 

112 Returns all members as a dictionary. 

113 

114 @return dictionary 

115 """ 

116 return {"id_rss": self.id_rss, 

117 "title": self.title, 

118 "guid": self.guid, 

119 "isPermaLink": self.isPermaLink, 

120 "link": self.link, 

121 "description": self.description, 

122 "pubDate": self.pubDate, 

123 "keywords": self.keywords, 

124 } 

125 

126 @staticmethod 

127 def schema_database_read(): 

128 """ 

129 Returns all members names and types as a dictionary. 

130 

131 @return dictionary 

132 """ 

133 return {0: ("id_rss", int), 

134 1: ("pubDate", datetime.datetime), 

135 2: ("title", str), 

136 3: ("guid", str), 

137 4: ("isPermaLink", int), 

138 5: ("link", str), 

139 6: ("description", str), 

140 7: ("keywords", str), 

141 8: ("id", int, "PRIMARYKEY", "AUTOINCREMENT")} 

142 

143 @property 

144 def schema_database(self): 

145 """ 

146 Returns all members names and types as a dictionary. 

147 

148 @return dictionary 

149 """ 

150 return {0: ("id_rss", int), 

151 1: ("pubDate", datetime.datetime), 

152 2: ("title", str), 

153 3: ("guid", str), 

154 4: ("isPermaLink", int), 

155 5: ("link", str), 

156 6: ("description", str), 

157 7: ("keywords", str), 

158 -1: ("id", int, "PRIMARYKEY", "AUTOINCREMENT")} 

159 

160 @property 

161 def asrow(self): 

162 """ 

163 Returns all the values as a row 

164 (following the schema given by @see me schema_database). 

165 

166 @return list of values 

167 """ 

168 return [self.id_rss if isinstance(self.id_rss, int) else self.id_rss.id, 

169 self.pubDate, 

170 self.title, 

171 self.guid, 

172 1 if self.isPermaLink else 0, 

173 self.link, 

174 self.description.replace("\r", "").replace("\n", " "), 

175 ",".join(self.keywords)] 

176 

177 @staticmethod 

178 def fill_table(db, tablename, iterator_on, skip_exception=False): 

179 """ 

180 Fills a table of a database, if the table does not exists, it creates it. 

181 

182 @param db database object (@see cl Database) 

183 @param tablename name of a table (created if it does not exists) 

184 @param iterator_on iterator_on on StreamRSS object 

185 @param skip_exception skip exception while inserting an element 

186 """ 

187 db.fill_table_with_objects(tablename, 

188 iterator_on, 

189 check_existence=True, 

190 skip_exception=skip_exception) 

191 

192 @property 

193 def pubDateformat(self): 

194 """ 

195 Returns the date to a given format. 

196 """ 

197 return self.pubDate.strftime(self._ftime) 

198 

199 @property 

200 def Status(self): 

201 """ 

202 Return the status. 

203 """ 

204 return self.status.get("status", "") if self.status is not None else "" 

205 

206 @property 

207 def StatusTime(self): 

208 """ 

209 Returns the status. 

210 """ 

211 return self.status.get("dtime", "") if self.status is not None else "" 

212 

213 @property 

214 def StatusTimeStr(self): 

215 """ 

216 Returns the status. 

217 """ 

218 return str(self.StatusTime).split()[0] 

219 

220 def get_html_status(self, thispage): 

221 """ 

222 Returns a status written in :epkg:`HTML`. 

223 

224 @param thispage the displayed page 

225 @return html string 

226 """ 

227 alls = [] 

228 for k in self.statusList: 

229 if self.status is not None and "status" in self.status and self.status[ 

230 "status"] == k: 

231 style = "poststatusextbyes" 

232 else: 

233 style = "poststatusextbno" 

234 code = """<a class="%s" href="%s" onmousedown="sendlog('status/{0.id}/%s')">%s</a>""" % ( 

235 style, thispage, k, k) 

236 alls.append(code) 

237 return "\n".join(alls) 

238 

239 template = """ 

240 <p class="%s">{0.pubDateformat}<a href="%s" onmousedown="sendlog('post/{0.id}/in')">{0.title}</a> 

241 <a href="{0.link}" target="_blank" onmousedown="sendlog('post/{0.id}/outimg')"> 

242 <img src="/arrowi.png" width="12px" /></a></p> 

243 """.replace(" ", "") 

244 

245 templateext = """ 

246 <p class="%s"><a href="{0.id_rss.htmlUrl}" 

247 target="_blank" onmousedown="sendlog('blog/{0.id_rss.id}/out')">{0.id_rss.titleb}</a></p> 

248 <p class="%s"><b>{0.pubDateformat} </b> 

249 <a href="%s" target="_blank" onmousedown="sendlog('post/{0.id}/out')">{0.title}</a></p> 

250 <p class="%s">{0.description}</p> 

251 <hr /> 

252 """.replace(" ", "") 

253 

254 templateextst = """ 

255 <p class="%s"><a href="{0.id_rss.htmlUrl}" 

256 target="_blank" onmousedown="sendlog('blog/{0.id_rss.id}/out')">{0.id_rss.titleb}</a></p> 

257 <p class="%s"><b>{0.pubDateformat} </b> 

258 <a href="%s" target="_blank" onmousedown="sendlog('post/{0.id}/out')">{0.title}</a></p> 

259 <p class="%s">{0.description}</p> 

260 <p class="%s">%s</p> 

261 <hr /> 

262 """.replace(" ", "") 

263 

264 templateShort = """ 

265 <tr><td class="%s">{0.StatusTimeStr}</td><td class="%s">{0.Status}</td> 

266 <td class="%s">{0.pubDateformat}<a href="%s" onmousedown="sendlog('post/{0.id}/in')">{0.title}</a> 

267 <a href="{0.link}" target="_blank" onmousedown="sendlog('post/{0.id}/outimg')"> 

268 <img src="/arrowi.png" width="12px" /></a></td></tr> 

269 """.replace(" ", "") 

270 

271 templateTable = """ 

272 <tr><td class="%s">{0.pubDateformat}<a href="%s" onmousedown="sendlog('post/{0.id}/in')">{0.title}</a> 

273 <a href="{0.link}" target="_blank" onmousedown="sendlog('post/{0.id}/outimg')"> 

274 <img src="/arrowi.png" width="12px" /></a></td></tr> 

275 """.replace(" ", "") 

276 

277 def html(self, template=None, 

278 action="{0.link}", 

279 style=None, 

280 styleblog=None, 

281 stylestatus=None, 

282 ftime="%Y-%m-%d", 

283 extended=False, 

284 style_desc="description", 

285 addlog=True, 

286 addcontent=False, 

287 addstatus=False, 

288 thispage=None): 

289 """ 

290 Displays the blogs in HTML format, the template contains two kinds of informations: 

291 - ``{0.member}``: this string will be replaced by the member 

292 

293 @param template html template 

294 @param action url to use when clicking on a blog 

295 @param style style of the paragraph containing the url, if None, 

296 it will be set to ``postitle`` or ``posttitleext`` 

297 @param styleblog style of the paragraph containing the url, if None, 

298 it will be set to ``posttitleexb`` 

299 @param ftime format time 

300 @param extended if True, display the title, 

301 if False, display everything 

302 @param style_desc style for the description 

303 @param addlog if True, ``link`` will contains a prefix to go through the server and be logged 

304 @param addcontent if True, the function will add some javascript code to make the content from the website appear. 

305 @param addstatus if True, add the status for this blog post 

306 @return html string 

307 

308 If the template is None, it will be replaced a default value 

309 (see the code and the variable ``template``). 

310 """ 

311 if template is None: 

312 if not extended: 

313 if style is None: 

314 style = "posttitle" 

315 template = BlogPost.template % (style, action) 

316 else: 

317 if style is None: 

318 style = "posttitleext" 

319 if styleblog is None: 

320 styleblog = "posttitleextb" 

321 if stylestatus is None: 

322 stylestatus = "poststatusextb" 

323 if addstatus: 

324 template = BlogPost.templateextst % ( 

325 styleblog, style, action, style_desc, stylestatus, self.get_html_status(thispage)) 

326 else: 

327 template = BlogPost.templateext % ( 

328 styleblog, style, action, style_desc) 

329 elif template == "status": 

330 template = BlogPost.templateShort % ( 

331 "posttitleext", "posttitleext", "posttitleextb", action) 

332 elif template == "table": 

333 template = BlogPost.templateTable % ("posttitleextb", action) 

334 elif not isinstance(template, str): 

335 raise Exception("expecting a format as a string") 

336 

337 self._ftime = ftime # for a property 

338 res = template.format(self) 

339 

340 if addcontent: 

341 res += """ 

342 <div id="cont%d"> 

343 <p>waiting...</p> 

344 </div> 

345 <script type="text/javascript"> 

346 try 

347 { 

348 loadDoc('%s', 'cont%d', false, '%s'); 

349 } 

350 catch (err) 

351 { 

352 document.write ("<p>loading error</p>") ; 

353 } 

354 </script> 

355 """ % (self.id, self.link, self.id, self.title) 

356 

357 return res 

358 

359 template_to_rss = jinja2.Template(dedent(""" 

360 <item> 

361 <title>{{title}}</title> 

362 <link>{{link}}</link> 

363 <guid isPermaLink="true">{{permalink}}</guid> 

364 <description>{{description}}</description> 

365 <pubDate>{{date}}</pubDate> 

366 </item> 

367 """)) 

368 

369 def to_rss_item(self): 

370 """ 

371 Converts the blog post into :epkg:`XML`. 

372 

373 @return string 

374 """ 

375 return BlogPost.template_to_rss.render( # pylint: disable=E1101 

376 title=self.title, link=self.link, 

377 permalink=self.isPermaLink, description=self.description, 

378 data=self.pubDate) 

379 

380 template_to_html = jinja2.Template(dedent(""" 

381 <h2>{{date.strftime("%Y-%m-%d")}} - {{title}}</h2> 

382 <p> 

383 {% if "`" in description %} 

384 <a href="{{link}}">HTML</a> - 

385 {% endif %} 

386 {{description}} 

387 </p> 

388 {% if "`" not in description %} 

389 <p><a href="{{link}}">source</a></p> 

390 {% endif %} 

391 """)) 

392 

393 def to_html_item(self): 

394 """ 

395 Renders the blog post into :epkg:`HTML`. 

396 

397 @return string 

398 """ 

399 return BlogPost.template_to_html.render( # pylint: disable=E1101 

400 title=self.title, link=self.link, 

401 permalink=self.isPermaLink, description=self.description, 

402 date=self.pubDate)