Coverage for webapp / blog / views.py: 23%

86 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2025-12-29 22:06 +0000

1import flask 

2import requests 

3 

4from canonicalwebteam import image_template 

5from canonicalwebteam.blog import ( 

6 BlogViews, 

7 BlogAPI, 

8 build_blueprint, 

9 NotFoundError, 

10) 

11from cache.cache_utility import redis_cache 

12from dateutil import parser 

13from requests.exceptions import RequestException 

14 

15 

16def init_blog(app, url_prefix): 

17 session = requests.Session() 

18 blog_api = BlogAPI( 

19 session=session, 

20 thumbnail_width=354, 

21 thumbnail_height=199, 

22 ) 

23 blog = build_blueprint( 

24 BlogViews( 

25 api=blog_api, 

26 blog_title="Snapcraft Blog", 

27 tag_ids=[2996], 

28 excluded_tags=[3184, 3265, 3408], 

29 ) 

30 ) 

31 

32 @blog.route("/api/snap-posts/<snap>") 

33 def snap_posts(snap): 

34 cached_articles_key = f"snap_posts:{snap}" 

35 cached_articles = redis_cache.get( 

36 cached_articles_key, expected_type=list 

37 ) 

38 if cached_articles: 

39 return flask.jsonify(cached_articles) 

40 

41 try: 

42 blog_tags = blog_api.get_tag_by_slug(f"sc:snap:{snap}") 

43 except NotFoundError: 

44 blog_tags = None 

45 

46 blog_articles = None 

47 articles = [] 

48 

49 if blog_tags: 

50 snapcraft_tag = blog_api.get_tag_by_slug("snapcraft.io") 

51 

52 try: 

53 blog_articles, total_pages = blog_api.get_articles( 

54 tags=blog_tags["id"], 

55 tags_exclude=[3184, 3265, 3408], 

56 per_page=3 - len(articles), 

57 ) 

58 except RequestException: 

59 blog_articles = [] 

60 

61 for article in blog_articles: 

62 if article["image"]: 

63 featured_media = image_template( 

64 url=article["image"]["source_url"], 

65 alt="", 

66 width="346", 

67 height="231", 

68 fill=True, 

69 hi_def=True, 

70 loading="auto", 

71 ) 

72 else: 

73 featured_media = None 

74 

75 url = f"/blog/{article['slug']}" 

76 

77 if snapcraft_tag["id"] not in article["tags"]: 

78 url = f"https://ubuntu.com{url}" 

79 

80 articles.append( 

81 { 

82 "slug": url, 

83 "title": article["title"]["rendered"], 

84 "image": featured_media, 

85 } 

86 ) 

87 redis_cache.set(cached_articles_key, articles, ttl=3600) 

88 return flask.jsonify(articles) 

89 

90 @blog.route("/api/series/<series>") 

91 def snap_series(series): 

92 cached_articles_key = f"snap_series:{series}" 

93 cached_articles = redis_cache.get( 

94 cached_articles_key, expected_type=list 

95 ) 

96 if cached_articles: 

97 return flask.jsonify(cached_articles) 

98 

99 blog_articles = None 

100 articles = [] 

101 

102 try: 

103 blog_articles, total_pages = blog_api.get_articles(series) 

104 except RequestException: 

105 blog_articles = [] 

106 

107 for article in blog_articles: 

108 articles.append( 

109 { 

110 "slug": article["slug"], 

111 "title": article["title"]["rendered"], 

112 } 

113 ) 

114 redis_cache.set(cached_articles_key, articles, ttl=3600) 

115 return flask.jsonify(articles) 

116 

117 @blog.context_processor 

118 def add_newsletter(): 

119 newsletter_subscribed = flask.request.args.get( 

120 "newsletter", default=False, type=bool 

121 ) 

122 

123 return {"newsletter_subscribed": newsletter_subscribed} 

124 

125 @blog.route("/sitemap.xml") 

126 def sitemap(): 

127 base_url = "https://snapcraft.io/blog" 

128 links = [] 

129 page = 1 

130 while True: 

131 url = ( 

132 f"https://ubuntu.com/blog/wp-json/wp/v2/posts?" 

133 f"tags=2996&per_page=100&page={page}" 

134 f"&tags_exclude=3184%2C3265%2C3408" 

135 ) 

136 

137 response = session.get(url) 

138 if response.status_code == 400: 

139 break 

140 

141 try: 

142 blog_response = response.json() 

143 except Exception: 

144 continue 

145 

146 for post in blog_response: 

147 try: 

148 date = ( 

149 parser.parse(post["date"]) 

150 .replace(tzinfo=None) 

151 .strftime("%Y-%m-%d") 

152 ) 

153 links.append( 

154 { 

155 "url": base_url + "/" + post["slug"], 

156 "last_udpated": date, 

157 } 

158 ) 

159 except Exception: 

160 continue 

161 

162 page = page + 1 

163 

164 xml_sitemap = flask.render_template( 

165 "sitemap/sitemap.xml", 

166 base_url=base_url, 

167 links=links, 

168 ) 

169 

170 response = flask.make_response(xml_sitemap) 

171 response.headers["Content-Type"] = "application/xml" 

172 response.headers["Cache-Control"] = "public, max-age=43200" 

173 

174 return response 

175 

176 app.register_blueprint(blog, url_prefix=url_prefix)