Coverage for webapp/snapcraft/views.py: 69%

84 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-25 22:09 +0000

1import flask 

2 

3from webapp.config import DEFAULT_ICON_URL 

4from webapp.llms import BASE_URL, store_llm 

5from webapp.snapcraft import logic 

6 

7 

8def snapcraft_blueprint(): 

9 snapcraft = flask.Blueprint("snapcraft", __name__) 

10 

11 @snapcraft.route("/") 

12 def homepage(): 

13 nps = flask.request.args.get("nps") 

14 

15 livestream = logic.get_livestreams() 

16 

17 return flask.render_template( 

18 "index.html", nps=nps, livestream=livestream 

19 ) 

20 

21 @snapcraft.route("/account.json") 

22 def get_account_json(): 

23 """ 

24 A JSON endpoint to request login status 

25 """ 

26 try: 

27 publisher = None 

28 

29 if "publisher" in flask.session: 

30 publisher = flask.session["publisher"] 

31 

32 response = {"publisher": publisher} 

33 response = flask.make_response(response) 

34 

35 # Unset the last_login_method cookie to avoid forcing 

36 response.set_cookie("last_login_method", "", expires=0) 

37 

38 response.headers["Cache-Control"] = "no-store" 

39 

40 return response 

41 except Exception: 

42 response = {"error": "Error fetching account information"} 

43 response = flask.make_response(response) 

44 response.headers["Cache-Control"] = "no-store" 

45 return response, 502 

46 

47 @snapcraft.route("/iot") 

48 def iot(): 

49 status_code = 200 

50 

51 icon_host = "https://dashboard.snapcraft.io/site_media/appmedia" 

52 

53 devices = [ 

54 { 

55 "package_name": "ubuntu-frame-osk", 

56 "icon_url": "/".join([icon_host, "2023/03/icon_2_Frame.png"]), 

57 "title": "Ubuntu Frame", 

58 "developer_name": "Canonical", 

59 "developer_link": "/publisher/canonical", 

60 "developer_validation": "verified", 

61 }, 

62 { 

63 "package_name": "mir-kiosk", 

64 "icon_url": "/".join( 

65 [icon_host, "2021/06/mir-sqr-stacked-orng.png"] 

66 ), 

67 "title": "mir-kiosk", 

68 "developer_name": "Canonical", 

69 "developer_link": "/publisher/canonical", 

70 "developer_validation": "verified", 

71 }, 

72 { 

73 "package_name": "edgexfoundry", 

74 "icon_url": "/".join([icon_host, "2018/12/icon_Hx6IyH0.png"]), 

75 "title": "Edgexfoundry", 

76 "developer_name": "Canonical", 

77 "developer_link": "/publisher/canonical", 

78 "developer_validation": "verified", 

79 }, 

80 { 

81 "package_name": "node-red", 

82 "icon_url": "/".join([icon_host, "2017/01/nr-hex_1.png"]), 

83 "title": "Node-Red", 

84 "developer_name": "Node-RED-Team (noderedteam)", 

85 "developer_link": "/publisher/noderedteam", 

86 "developer_validation": "verified", 

87 }, 

88 { 

89 "package_name": "bluez", 

90 "icon_url": "/".join( 

91 [icon_host, "2020/05/bluez-logo-2.jpg.png"] 

92 ), 

93 "title": "bluez", 

94 "developer_name": "Canonical", 

95 "developer_link": "/publisher/canonical", 

96 "developer_validation": "verified", 

97 }, 

98 { 

99 "package_name": "zwave-js-ui", 

100 "icon_url": "/".join( 

101 [icon_host, "2022/10/app_logo-svg_2.svg.png"] 

102 ), 

103 "title": "Zwave JS UI", 

104 "developer_name": "Giaever.online (giaever-online)", 

105 "developer_link": "/publisher/giaever-online", 

106 }, 

107 { 

108 "package_name": "ubports-installer", 

109 "icon_url": "/".join( 

110 [icon_host, "2017/09/256x256_h3aYso1.png"] 

111 ), 

112 "title": "ubports-installer", 

113 "developer_name": "UBports", 

114 "developer_link": "/publisher/ubports", 

115 }, 

116 { 

117 "package_name": "librepcb", 

118 "icon_url": "/".join([icon_host, "2022/10/librepcb.png"]), 

119 "title": "LibrePCB", 

120 "developer_name": "librepcb", 

121 "developer_link": "/publisher/librepcb", 

122 "developer_validation": "verified", 

123 }, 

124 { 

125 "package_name": "ammp-edge", 

126 "icon_url": "/".join( 

127 [icon_host, "2020/12/glyph-rounder-square-180px.png"] 

128 ), 

129 "title": "ammp-edge", 

130 "developer_name": "AMMP Technologies (ammp)", 

131 "developer_link": "/publisher/ammp", 

132 }, 

133 { 

134 "package_name": "pi-bluetooth", 

135 "icon_url": DEFAULT_ICON_URL, 

136 "title": "pi-bluetooth", 

137 "developer_name": "Dave Jones (waveform)", 

138 "developer_link": "/publisher/waveform", 

139 }, 

140 ] 

141 

142 robotics = [ 

143 { 

144 "package_name": "arduino", 

145 "icon_url": "/".join([icon_host, "2020/02/icon_s4HbwJl.png"]), 

146 "title": "Arduino IDE", 

147 "developer_name": "Snapcrafters", 

148 "developer_link": "/publisher/snapcrafters", 

149 "developer_validation": "starred", 

150 }, 

151 { 

152 "package_name": "rosbot-xl", 

153 "icon_url": "/".join([icon_host, "2024/06/rosbot-xl.png"]), 

154 "title": "ROSbot XL", 

155 "developer_name": "Husarion", 

156 "developer_link": "/publisher/husarion", 

157 "developer_validation": "verified", 

158 }, 

159 { 

160 "package_name": "rosbot-xl-teleop", 

161 "icon_url": "/".join( 

162 [icon_host, "2023/10/popr512x512px_rosbot_xl_teleop.png"] 

163 ), 

164 "title": "ROSbot XL: teleop", 

165 "developer_name": "Husarion", 

166 "developer_link": "/publisher/husarion", 

167 "developer_validation": "verified", 

168 }, 

169 { 

170 "package_name": "webots", 

171 "icon_url": "/".join([icon_host, "2019/08/webots.png"]), 

172 "title": "Webots", 

173 "developer_name": "Cyberbotics", 

174 "developer_link": "/publisher/cyberbotics", 

175 }, 

176 { 

177 "package_name": "gazebo", 

178 "icon_url": "/".join([icon_host, "2022/05/icon.svg.png"]), 

179 "title": "gazebo", 

180 "developer_name": ( 

181 "Ubuntu Robotics Community (ubuntu-robotics-community)" 

182 ), 

183 "developer_link": "/publisher/ubuntu-robotics-community", 

184 "developer_validation": "verified", 

185 }, 

186 { 

187 "package_name": "ros2-cli", 

188 "icon_url": "/".join( 

189 [icon_host, "2023/02/ros2-cli_icon_1.png"] 

190 ), 

191 "title": "ros2-cli", 

192 "developer_name": ( 

193 "Ubuntu Robotics Community (ubuntu-robotics-community)" 

194 ), 

195 "developer_link": "/publisher/ubuntu-robotics-community", 

196 "developer_validation": "verified", 

197 }, 

198 { 

199 "package_name": "vulcanexus-router", 

200 "icon_url": "/".join([icon_host, "2023/05/V-DDSRouter.png"]), 

201 "title": "Vulcanexus Router", 

202 "developer_name": "eProsima", 

203 "developer_link": "/publisher/eprosima", 

204 }, 

205 { 

206 "package_name": "bow-webots", 

207 "icon_url": DEFAULT_ICON_URL, 

208 "title": "BOW Webots", 

209 "developer_name": "Daniel Camilleri (bow-robotics)", 

210 "developer_link": "/publisher/bow-robotics", 

211 }, 

212 { 

213 "package_name": "foxglove-studio", 

214 "icon_url": "/".join([icon_host, "2022/07/fs-icon.svg.png"]), 

215 "title": "foxglove-studio", 

216 "developer_name": "Roman Shtylman (roman-foxglove)", 

217 "developer_link": "/publisher/roman-foxglove", 

218 }, 

219 { 

220 "package_name": "husarion-ouster", 

221 "icon_url": "/".join( 

222 [icon_host, "2023/10/husarion-ouster.png"] 

223 ), 

224 "title": "husarion-ouster", 

225 "developer_name": "Husarion", 

226 "developer_link": "/publisher/husarion", 

227 "developer_validation": "verified", 

228 }, 

229 ] 

230 

231 smart_home = [ 

232 { 

233 "package_name": "openhab", 

234 "icon_url": "/".join([icon_host, "2017/11/favicon.png"]), 

235 "title": "openhab", 

236 "developer_name": "openHAB Foundation e.V. (openhab)", 

237 "developer_link": "/publisher/openhab", 

238 }, 

239 { 

240 "package_name": "homebridge", 

241 "icon_url": "/".join([icon_host, "2018/10/Logo2x.png"]), 

242 "title": "homebridge", 

243 "developer_name": "Ondrej Kubik (ondra)", 

244 }, 

245 { 

246 "package_name": "home-assistant-snap", 

247 "icon_url": "/".join( 

248 [icon_host, "2020/07/favicon-192x192.png"] 

249 ), 

250 "title": "Home Assistant", 

251 "developer_name": "Giaever.online (giaever-online)", 

252 "developer_link": "/publisher/giaever-online", 

253 }, 

254 { 

255 "package_name": "security-bear", 

256 "icon_url": "/".join( 

257 [icon_host, "2020/11/security-bear_Logo.png"] 

258 ), 

259 "title": "security-bear", 

260 "developer_name": "CyBear Jinni (cybearjinni)", 

261 "developer_link": "/publisher/cybearjinni", 

262 }, 

263 { 

264 "package_name": "chip-tool", 

265 "icon_url": "/".join([icon_host, "2023/01/1F3E0_color.png"]), 

266 "title": "chip-tool", 

267 "developer_name": "Canonical IoT Labs (canonical-iot-labs)", 

268 "developer_link": "/publisher/canonical-iot-labs", 

269 }, 

270 { 

271 "package_name": "openthread-border-router", 

272 "icon_url": "/".join( 

273 [icon_host, "2023/09/ThreadLogo-stort-1.png"] 

274 ), 

275 "title": "openthread-border-router", 

276 "developer_name": "Canonical IoT Labs (canonical-iot-labs)", 

277 "developer_link": "/publisher/canonical-iot-labs", 

278 }, 

279 { 

280 "package_name": "matter-bridge-tapo-lighting", 

281 "icon_url": "/".join( 

282 [icon_host, "2023/01/1F3E0_color_8tMXOjP.png"] 

283 ), 

284 "title": "matter-bridge-tapo-lighting", 

285 "developer_name": "Canonical IoT Labs (canonical-iot-labs)", 

286 "developer_link": "/publisher/canonical-iot-labs", 

287 }, 

288 { 

289 "package_name": "matter-pi-gpio-commander", 

290 "icon_url": "/".join([icon_host, "2023/03/E1C7_color.png"]), 

291 "title": "matter-pi-gpio-commander", 

292 "developer_name": "Canonical IoT Labs (canonical-iot-labs)", 

293 "developer_link": "/publisher/canonical-iot-labs", 

294 }, 

295 ] 

296 

297 networking = [ 

298 { 

299 "package_name": "mosquitto", 

300 "icon_url": "/".join( 

301 [icon_host, "2018/08/mosquitto-logo-only.svg.png"] 

302 ), 

303 "title": "mosquitto", 

304 "developer_name": "Mosquitto Team (mosquitto)", 

305 "developer_link": "/publisher/mosquitto", 

306 "developer_validation": "verified", 

307 }, 

308 { 

309 "package_name": "domotzpro-agent-publicstore", 

310 "icon_url": "/".join( 

311 [icon_host, "2019/03/new_domotz_icon.png"] 

312 ), 

313 "title": "Domotz Pro Agent", 

314 "developer_name": "Domotz (domotzpublicstore)", 

315 "developer_link": "/publisher/domotzpublicstore", 

316 "developer_validation": "verified", 

317 }, 

318 { 

319 "package_name": "adguard-home", 

320 "icon_url": "/".join([icon_host, "2020/04/256.png"]), 

321 "title": "AdGuard Home", 

322 "developer_name": "AdGuard (ameshkov)", 

323 "developer_link": "/publisher/ameshkov", 

324 "developer_validation": "verified", 

325 }, 

326 { 

327 "package_name": "flexran", 

328 "icon_url": "/".join([icon_host, "2018/04/m5g-flexran.png"]), 

329 "title": "flexran", 

330 "developer_name": "Mosaic 5G (mosaic-5g)", 

331 "developer_link": "/publisher/mosaic-5g", 

332 }, 

333 { 

334 "package_name": "modem-manager", 

335 "icon_url": "/".join([icon_host, "2020/05/mm-logo.png"]), 

336 "title": "modem-manager", 

337 "developer_name": "Canonical", 

338 "developer_link": "/publisher/canonical", 

339 "developer_validation": "verified", 

340 }, 

341 { 

342 "package_name": "snap-store-proxy", 

343 "icon_url": "/".join( 

344 [icon_host, "2018/09/Snapcraft_Proxy_Aubergine-256.png"] 

345 ), 

346 "title": "snap-store-proxy", 

347 "developer_name": "Canonical", 

348 "developer_link": "/publisher/canonical", 

349 "developer_validation": "verified", 

350 }, 

351 ] 

352 

353 board_images = [ 

354 { 

355 "package_name": "pc", 

356 "icon_url": "/".join([icon_host, "2016/07/icon_30.png"]), 

357 "title": "PC", 

358 "developer_name": "Canonical", 

359 "developer_link": "/publisher/canonical", 

360 "developer_validation": "verified", 

361 }, 

362 { 

363 "package_name": "rpi-imager", 

364 "icon_url": "/".join([icon_host, "2020/03/rpi-imager.png"]), 

365 "title": "rpi-imager", 

366 "developer_name": "Dave Jones (waveform)", 

367 "developer_link": "/publisher/waveform", 

368 }, 

369 { 

370 "package_name": "pi-desktop", 

371 "icon_url": DEFAULT_ICON_URL, 

372 "title": "pi-desktop", 

373 "developer_name": "Canonical", 

374 "developer_link": "/publisher/canonical", 

375 "develper_validation": "verified", 

376 }, 

377 { 

378 "package_name": "pi", 

379 "icon_url": DEFAULT_ICON_URL, 

380 "title": "pi", 

381 "developer_name": "Canonical", 

382 "developer_link": "/publisher/canonical", 

383 "developer_validation": "verified", 

384 }, 

385 { 

386 "package_name": "pi2", 

387 "icon_url": "/".join([icon_host, "2015/04/berry.jpg.png"]), 

388 "title": "pi2", 

389 "developer_name": "Canonical", 

390 "developer_link": "/publisher/canonical", 

391 "developer_validation": "verified", 

392 }, 

393 { 

394 "package_name": "pi3", 

395 "icon_url": DEFAULT_ICON_URL, 

396 "title": "pi3", 

397 "developer_name": "Canonical", 

398 "developer_link": "/publisher/canonical", 

399 "developer_validation": "verified", 

400 }, 

401 ] 

402 

403 context = { 

404 "devices": devices, 

405 "robotics": robotics, 

406 "smart_home": smart_home, 

407 "networking": networking, 

408 "board_images": board_images, 

409 } 

410 

411 return ( 

412 flask.render_template("store/categories/iot.html", **context), 

413 status_code, 

414 ) 

415 

416 @snapcraft.route("/about") 

417 def about(): 

418 return flask.render_template("about/index.html") 

419 

420 @snapcraft.route("/about/publish") 

421 def about_publish(): 

422 return flask.render_template("about/publish.html") 

423 

424 @snapcraft.route("/about/listing") 

425 def about_listing(): 

426 return flask.render_template("about/listing.html") 

427 

428 @snapcraft.route("/about/release") 

429 def about_release(): 

430 return flask.render_template("about/release.html") 

431 

432 @snapcraft.route("/about/publicise") 

433 def about_publicise(): 

434 return flask.render_template("about/publicise.html") 

435 

436 @snapcraft.route("/about/contact-us") 

437 def about_contact(): 

438 return flask.render_template("contact-us.html") 

439 

440 @snapcraft.route("/about/thank-you") 

441 def about_thankyou(): 

442 return flask.render_template("thank-you.html") 

443 

444 @snapcraft.route("/community") 

445 def community_redirect(): 

446 return flask.redirect("/") 

447 

448 @snapcraft.route("/create") 

449 def create_redirect(): 

450 return flask.redirect( 

451 "https://documentation.ubuntu.com/snapcraft/stable" 

452 "/tutorials/craft-a-snap/", 

453 code=301, 

454 ) 

455 

456 @snapcraft.route("/build") 

457 def build(): 

458 status_code = 200 

459 

460 return flask.render_template("snapcraft/build.html"), status_code 

461 

462 @snapcraft.route("/sitemap.xml") 

463 def sitemap(): 

464 xml_sitemap = flask.render_template( 

465 "sitemap/sitemap-index.xml", 

466 base_url=BASE_URL, 

467 ) 

468 response = flask.make_response(xml_sitemap) 

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

470 

471 return response 

472 

473 @snapcraft.route("/sitemap-links.xml") 

474 def sitemap_links(): 

475 links = [ 

476 {"url": BASE_URL + path} for path in store_llm.sitemap_paths() 

477 ] 

478 

479 xml_sitemap = flask.render_template( 

480 "sitemap/sitemap.xml", 

481 base_url=BASE_URL, 

482 links=links, 

483 ) 

484 response = flask.make_response(xml_sitemap) 

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

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

487 

488 return response 

489 

490 return snapcraft