Coverage for src/pyrsslocal/rss/rss_blogpost.py: 84%
111 statements
« prev ^ index » next coverage.py v7.1.0, created at 2024-04-30 08:45 +0200
« prev ^ index » next coverage.py v7.1.0, created at 2024-04-30 08:45 +0200
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
11class BlogPost:
13 """
14 A blog post.
16 ::
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><p> J'ecoutais une em....</description>
23 <pubDate>2013-06-30 00:00:00</pubDate>
24 </item>
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 """
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"]
67 if self.id_rss is None:
68 raise ValueError("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")
77 if isinstance(self.pubDate, str):
78 self.pubDate = str2datetime(self.pubDate)
80 def add_status(self, status):
81 """
82 Attaches a dictionary representing the status.
84 @param status dictionary
85 """
86 self.status = status
88 def __str__(self):
89 """
90 usual
91 """
92 return "%s: %s (from %s)" % (
93 str(self.pubDate), self.title, self.id_rss)
95 @property
96 def index(self):
97 """
98 Defines the column to use as an index.
99 """
100 return "guid"
102 @property
103 def indexes(self):
104 """
105 Defines other indexes to create.
106 """
107 return ["id_rss"]
109 @property
110 def asdict(self):
111 """
112 Returns all members as a dictionary.
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 }
126 @staticmethod
127 def schema_database_read():
128 """
129 Returns all members names and types as a dictionary.
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")}
143 @property
144 def schema_database(self):
145 """
146 Returns all members names and types as a dictionary.
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")}
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).
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)]
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.
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)
192 @property
193 def pubDateformat(self):
194 """
195 Returns the date to a given format.
196 """
197 return self.pubDate.strftime(self._ftime)
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 ""
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 ""
213 @property
214 def StatusTimeStr(self):
215 """
216 Returns the status.
217 """
218 return str(self.StatusTime).split()[0]
220 def get_html_status(self, thispage):
221 """
222 Returns a status written in :epkg:`HTML`.
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)
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(" ", "")
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(" ", "")
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(" ", "")
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(" ", "")
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(" ", "")
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
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
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 TypeError("expecting a format as a string")
337 self._ftime = ftime # for a property
338 res = template.format(self)
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)
357 return res
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 """))
369 def to_rss_item(self):
370 """
371 Converts the blog post into :epkg:`XML`.
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)
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 """))
393 def to_html_item(self):
394 """
395 Renders the blog post into :epkg:`HTML`.
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)