Coverage for webapp / endpoints / publisher / listing.py: 83%

110 statements  

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

1# Standard library 

2from json import loads 

3 

4# Packages 

5import flask 

6from canonicalwebteam.exceptions import ( 

7 StoreApiError, 

8 StoreApiResponseErrorList, 

9) 

10from canonicalwebteam.store_api.dashboard import Dashboard 

11from canonicalwebteam.store_api.devicegw import DeviceGW 

12 

13# Local 

14from webapp import helpers 

15from webapp.helpers import api_session 

16from webapp.decorators import login_required 

17from webapp.publisher.snaps import logic 

18from webapp.store.logic import ( 

19 get_categories, 

20) 

21 

22dashboard = Dashboard(api_session) 

23device_gateway = DeviceGW("snap", api_session) 

24 

25 

26@login_required 

27def get_listing_data(snap_name): 

28 snap_details = dashboard.get_snap_info(flask.session, snap_name) 

29 details_metrics_enabled = snap_details["public_metrics_enabled"] 

30 details_blacklist = snap_details.get("public_metrics_blacklist", []) 

31 

32 # Filter icon & screenshot urls from the media set. 

33 icon_urls, screenshot_urls, banner_urls = logic.categorise_media( 

34 snap_details["media"] 

35 ) 

36 

37 primary_website = "" 

38 if ( 

39 "website" in snap_details["links"] 

40 and len(snap_details["links"]["website"]) > 0 

41 ): 

42 primary_website = snap_details["links"]["website"][0] 

43 

44 websites = [] 

45 if "website" in snap_details["links"]: 

46 if len(snap_details["links"]["website"]) > 1: 

47 snap_details["links"]["website"].pop(0) 

48 for website in snap_details["links"]["website"]: 

49 websites.append({"url": website}) 

50 

51 def format_links(key): 

52 result = [] 

53 if key in snap_details["links"]: 

54 for url in snap_details["links"][key]: 

55 result.append({"url": url}) 

56 return result 

57 

58 licenses = [] 

59 for license in helpers.get_licenses(): 

60 licenses.append({"key": license["licenseId"], "name": license["name"]}) 

61 

62 license = snap_details["license"] 

63 license_type = "custom" 

64 

65 if " AND " not in license.upper() and " WITH " not in license.upper(): 

66 license_type = "simple" 

67 

68 try: 

69 categories_results = device_gateway.get_categories() 

70 except StoreApiError: 

71 categories_results = [] 

72 

73 categories = sorted( 

74 get_categories(categories_results), 

75 key=lambda category: category["slug"], 

76 ) 

77 

78 snap_categories = logic.replace_reserved_categories_key( 

79 snap_details["categories"] 

80 ) 

81 

82 snap_categories = logic.filter_categories(snap_categories) 

83 

84 snap_categories["categories"] = [ 

85 category["name"] for category in snap_categories["categories"] 

86 ] 

87 

88 filename = "publisher/content/listing_tour.yaml" 

89 tour_steps = helpers.get_yaml(filename, typ="rt") 

90 

91 primary_category = "" 

92 if len(snap_categories["categories"]) > 0: 

93 primary_category = snap_categories["categories"][0] 

94 

95 secondary_category = "" 

96 if len(snap_categories["categories"]) > 1: 

97 secondary_category = snap_categories["categories"][1] 

98 

99 video_urls = None 

100 

101 if len(snap_details["video_urls"]) > 0: 

102 video_urls = snap_details["video_urls"][0] 

103 

104 context = { 

105 "title": snap_details["title"], 

106 "video_urls": video_urls, 

107 "summary": snap_details["summary"], 

108 "description": snap_details["description"], 

109 "categories": categories, 

110 "primary_category": primary_category, 

111 "secondary_category": secondary_category, 

112 "websites": websites, 

113 "contacts": format_links("contact"), 

114 "donations": format_links("donations"), 

115 "source_code": format_links("source"), 

116 "issues": format_links("issues"), 

117 "primary_website": primary_website, 

118 "snap_id": snap_details["snap_id"], 

119 "public_metrics_enabled": details_metrics_enabled, 

120 "public_metrics_blacklist": details_blacklist, 

121 "license": license, 

122 "license_type": license_type, 

123 "licenses": licenses, 

124 "icon_url": icon_urls[0] if icon_urls else None, 

125 "screenshot_urls": screenshot_urls, 

126 "banner_urls": banner_urls, 

127 "update_metadata_on_release": snap_details[ 

128 "update_metadata_on_release" 

129 ], 

130 "tour_steps": tour_steps, 

131 } 

132 

133 res = {} 

134 res["data"] = context 

135 res["message"] = "" 

136 res["success"] = True 

137 

138 return flask.jsonify(res) 

139 

140 

141@login_required 

142def post_listing_data(snap_name): 

143 changes = None 

144 changed_fields = flask.request.form.get("changes") 

145 

146 if changed_fields: 

147 changes = loads(changed_fields) 

148 

149 if changes: 

150 snap_id = flask.request.form.get("snap_id") 

151 error_list = [] 

152 

153 if "images" in changes: 

154 # Add existing screenshots 

155 current_screenshots = dashboard.snap_screenshots( 

156 flask.session, snap_id 

157 ) 

158 

159 icon_input = ( 

160 flask.request.files.get("icon") 

161 if flask.request.files.get("icon") 

162 else None 

163 ) 

164 screenshots_input = [ 

165 s if s else None 

166 for s in flask.request.files.getlist("screenshots") 

167 ] 

168 banner_image_input = ( 

169 flask.request.files.get("banner-image") 

170 if flask.request.files.get("banner-image") 

171 else None 

172 ) 

173 

174 images_json, images_files = logic.build_changed_images( 

175 changes["images"], 

176 current_screenshots, 

177 icon_input, 

178 screenshots_input, 

179 banner_image_input, 

180 ) 

181 

182 try: 

183 dashboard.snap_screenshots( 

184 flask.session, snap_id, images_json, images_files 

185 ) 

186 except StoreApiResponseErrorList as api_response_error_list: 

187 if api_response_error_list.status_code != 404: 

188 error_list = error_list + api_response_error_list.errors 

189 

190 body_json = logic.filter_changes_data(changes) 

191 

192 if body_json: 

193 if "description" in body_json: 

194 body_json["description"] = logic.remove_invalid_characters( 

195 body_json["description"] 

196 ) 

197 

198 try: 

199 dashboard.snap_metadata(flask.session, snap_id, body_json) 

200 except StoreApiResponseErrorList as api_response_error_list: 

201 if api_response_error_list.status_code != 404: 

202 error_list = error_list + api_response_error_list.errors 

203 

204 if error_list: 

205 try: 

206 snap_details = dashboard.get_snap_info( 

207 flask.session, snap_name 

208 ) 

209 except StoreApiResponseErrorList as api_response_error_list: 

210 if api_response_error_list.status_code == 404: 

211 return flask.abort( 

212 404, "No snap named {}".format(snap_name) 

213 ) 

214 else: 

215 error_list = error_list + api_response_error_list.errors 

216 

217 licenses = [] 

218 for license in helpers.get_licenses(): 

219 licenses.append( 

220 {"key": license["licenseId"], "name": license["name"]} 

221 ) 

222 

223 license = snap_details["license"] 

224 

225 snap_categories = logic.replace_reserved_categories_key( 

226 snap_details["categories"] 

227 ) 

228 

229 snap_categories = logic.filter_categories(snap_categories) 

230 

231 res = {"success": True, "errors": error_list} 

232 

233 return flask.make_response(res, 200) 

234 

235 return flask.make_response({"success": True}, 200)