Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import flask 

2import prometheus_client 

3from talisker import logging 

4 

5from webapp.snapcraft import logic 

6 

7users_with_js = prometheus_client.Counter( 

8 "users_with_js", "A counter of sessions with JS" 

9) 

10users_without_js = prometheus_client.Counter( 

11 "users_without_js", "A counter of sessions without JS" 

12) 

13 

14 

15def snapcraft_blueprint(): 

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

17 

18 @snapcraft.route("/") 

19 def homepage(): 

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

21 

22 livestream = logic.get_livestreams() 

23 

24 return flask.render_template( 

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

26 ) 

27 

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

29 def get_account_json(): 

30 """ 

31 A JSON endpoint to request login status 

32 """ 

33 try: 

34 publisher = None 

35 

36 if "publisher" in flask.session: 

37 publisher = flask.session["publisher"] 

38 

39 response = {"publisher": publisher} 

40 response = flask.make_response(response) 

41 

42 # Unset the last_login_method cookie to avoid forcing 

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

44 

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

46 

47 return response 

48 except Exception as e: 

49 logging.getLogger("talisker.wsgi").error( 

50 "Error with session: %s", e 

51 ) 

52 

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

54 response = flask.make_response(response) 

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

56 return response, 502 

57 

58 @snapcraft.route("/iot") 

59 def iot(): 

60 status_code = 200 

61 

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

63 assets_host = "https://assets.ubuntu.com/v1" 

64 

65 devices = [ 

66 { 

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

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

69 "title": "Ubuntu Frame", 

70 "developer_name": "Canonical", 

71 "developer_link": "/publisher/canonical", 

72 "developer_validation": "verified", 

73 }, 

74 { 

75 "package_name": "mir-kiosk", 

76 "icon_url": "/".join( 

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

78 ), 

79 "title": "mir-kiosk", 

80 "developer_name": "Canonical", 

81 "developer_link": "/publisher/canonical", 

82 "developer_validation": "verified", 

83 }, 

84 { 

85 "package_name": "edgexfoundry", 

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

87 "title": "Edgexfoundry", 

88 "developer_name": "Canonical", 

89 "developer_link": "/publisher/canonical", 

90 "developer_validation": "verified", 

91 }, 

92 { 

93 "package_name": "node-red", 

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

95 "title": "Node-Red", 

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

97 "developer_link": "/publisher/noderedteam", 

98 "developer_validation": "verified", 

99 }, 

100 { 

101 "package_name": "bluez", 

102 "icon_url": "/".join( 

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

104 ), 

105 "title": "bluez", 

106 "developer_name": "Canonical", 

107 "developer_link": "/publisher/canonical", 

108 "developer_validation": "verified", 

109 }, 

110 { 

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

112 "icon_url": "/".join( 

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

114 ), 

115 "title": "Zwave JS UI", 

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

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

118 }, 

119 { 

120 "package_name": "ubports-installer", 

121 "icon_url": "/".join( 

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

123 ), 

124 "title": "ubports-installer", 

125 "developer_name": "UBports", 

126 "developer_link": "/publisher/ubports", 

127 }, 

128 { 

129 "package_name": "librepcb", 

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

131 "title": "LibrePCB", 

132 "developer_name": "librepcb", 

133 "developer_link": "/publisher/librepcb", 

134 "developer_validation": "verified", 

135 }, 

136 { 

137 "package_name": "ammp-edge", 

138 "icon_url": "/".join( 

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

140 ), 

141 "title": "ammp-edge", 

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

143 "developer_link": "/publisher/ammp", 

144 }, 

145 { 

146 "package_name": "pi-bluetooth", 

147 "icon_url": "/".join( 

148 [assets_host, "be6eb412-snapcraft-missing-icon.svg"] 

149 ), 

150 "title": "pi-bluetooth", 

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

152 "developer_link": "/publisher/waveform", 

153 }, 

154 ] 

155 

156 robotics = [ 

157 { 

158 "package_name": "arduino", 

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

160 "title": "Arduino IDE", 

161 "developer_name": "Snapcrafters", 

162 "developer_link": "/publisher/snapcrafters", 

163 "developer_validation": "starred", 

164 }, 

165 { 

166 "package_name": "rosbot-xl", 

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

168 "title": "ROSbot XL", 

169 "developer_name": "Husarion", 

170 "developer_link": "/publisher/husarion", 

171 "developer_validation": "verified", 

172 }, 

173 { 

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

175 "icon_url": "/".join( 

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

177 ), 

178 "title": "ROSbot XL: teleop", 

179 "developer_name": "Husarion", 

180 "developer_link": "/publisher/husarion", 

181 "developer_validation": "verified", 

182 }, 

183 { 

184 "package_name": "webots", 

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

186 "title": "Webots", 

187 "developer_name": "Cyberbotics", 

188 "developer_link": "/publisher/cyberbotics", 

189 }, 

190 { 

191 "package_name": "gazebo", 

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

193 "title": "gazebo", 

194 "developer_name": ( 

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

196 ), 

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

198 "developer_validation": "verified", 

199 }, 

200 { 

201 "package_name": "ros2-cli", 

202 "icon_url": "/".join( 

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

204 ), 

205 "title": "ros2-cli", 

206 "developer_name": ( 

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

208 ), 

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

210 "developer_validation": "verified", 

211 }, 

212 { 

213 "package_name": "vulcanexus-router", 

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

215 "title": "Vulcanexus Router", 

216 "developer_name": "eProsima", 

217 "developer_link": "/publisher/eprosima", 

218 }, 

219 { 

220 "package_name": "bow-webots", 

221 "icon_url": "/".join( 

222 [assets_host, "be6eb412-snapcraft-missing-icon.svg"] 

223 ), 

224 "title": "BOW Webots", 

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

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

227 }, 

228 { 

229 "package_name": "foxglove-studio", 

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

231 "title": "foxglove-studio", 

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

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

234 }, 

235 { 

236 "package_name": "husarion-ouster", 

237 "icon_url": "/".join( 

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

239 ), 

240 "title": "husarion-ouster", 

241 "developer_name": "Husarion", 

242 "developer_link": "/publisher/husarion", 

243 "developer_validation": "verified", 

244 }, 

245 ] 

246 

247 smart_home = [ 

248 { 

249 "package_name": "openhab", 

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

251 "title": "openhab", 

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

253 "developer_link": "/publisher/openhab", 

254 }, 

255 { 

256 "package_name": "homebridge", 

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

258 "title": "homebridge", 

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

260 }, 

261 { 

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

263 "icon_url": "/".join( 

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

265 ), 

266 "title": "Home Assistant", 

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

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

269 }, 

270 { 

271 "package_name": "security-bear", 

272 "icon_url": "/".join( 

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

274 ), 

275 "title": "security-bear", 

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

277 "developer_link": "/publisher/cybearjinni", 

278 }, 

279 { 

280 "package_name": "chip-tool", 

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

282 "title": "chip-tool", 

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

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

285 }, 

286 { 

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

288 "icon_url": "/".join( 

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

290 ), 

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

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

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

294 }, 

295 { 

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

297 "icon_url": "/".join( 

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

299 ), 

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

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

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

303 }, 

304 { 

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

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

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

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

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

310 }, 

311 ] 

312 

313 networking = [ 

314 { 

315 "package_name": "mosquitto", 

316 "icon_url": "/".join( 

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

318 ), 

319 "title": "mosquitto", 

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

321 "developer_link": "/publisher/mosquitto", 

322 "developer_validation": "verified", 

323 }, 

324 { 

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

326 "icon_url": "/".join( 

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

328 ), 

329 "title": "Domotz Pro Agent", 

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

331 "developer_link": "/publisher/domotzpublicstore", 

332 "developer_validation": "verified", 

333 }, 

334 { 

335 "package_name": "adguard-home", 

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

337 "title": "AdGuard Home", 

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

339 "developer_link": "/publisher/ameshkov", 

340 "developer_validation": "verified", 

341 }, 

342 { 

343 "package_name": "flexran", 

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

345 "title": "flexran", 

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

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

348 }, 

349 { 

350 "package_name": "modem-manager", 

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

352 "title": "modem-manager", 

353 "developer_name": "Canonical", 

354 "developer_link": "/publisher/canonical", 

355 "developer_validation": "verified", 

356 }, 

357 { 

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

359 "icon_url": "/".join( 

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

361 ), 

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

363 "developer_name": "Canonical", 

364 "developer_link": "/publisher/canonical", 

365 "developer_validation": "verified", 

366 }, 

367 ] 

368 

369 board_images = [ 

370 { 

371 "package_name": "pc", 

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

373 "title": "PC", 

374 "developer_name": "Canonical", 

375 "developer_link": "/publisher/canonical", 

376 "developer_validation": "verified", 

377 }, 

378 { 

379 "package_name": "rpi-imager", 

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

381 "title": "rpi-imager", 

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

383 "developer_link": "/publisher/waveform", 

384 }, 

385 { 

386 "package_name": "pi-desktop", 

387 "icon_url": "/".join( 

388 [assets_host, "be6eb412-snapcraft-missing-icon.svg"] 

389 ), 

390 "title": "pi-desktop", 

391 "developer_name": "Canonical", 

392 "developer_link": "/publisher/canonical", 

393 "develper_validation": "verified", 

394 }, 

395 { 

396 "package_name": "pi", 

397 "icon_url": "/".join( 

398 [assets_host, "be6eb412-snapcraft-missing-icon.svg"] 

399 ), 

400 "title": "pi", 

401 "developer_name": "Canonical", 

402 "developer_link": "/publisher/canonical", 

403 "developer_validation": "verified", 

404 }, 

405 { 

406 "package_name": "pi2", 

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

408 "title": "pi2", 

409 "developer_name": "Canonical", 

410 "developer_link": "/publisher/canonical", 

411 "developer_validation": "verified", 

412 }, 

413 { 

414 "package_name": "pi3", 

415 "icon_url": "/".join( 

416 [assets_host, "be6eb412-snapcraft-missing-icon.svg"] 

417 ), 

418 "title": "pi3", 

419 "developer_name": "Canonical", 

420 "developer_link": "/publisher/canonical", 

421 "developer_validation": "verified", 

422 }, 

423 ] 

424 

425 context = { 

426 "devices": devices, 

427 "robotics": robotics, 

428 "smart_home": smart_home, 

429 "networking": networking, 

430 "board_images": board_images, 

431 } 

432 

433 return ( 

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

435 status_code, 

436 ) 

437 

438 @snapcraft.route("/about") 

439 def about(): 

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

441 

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

443 def about_publish(): 

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

445 

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

447 def about_listing(): 

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

449 

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

451 def about_release(): 

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

453 

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

455 def about_publicise(): 

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

457 

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

459 def about_contact(): 

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

461 

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

463 def about_thankyou(): 

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

465 

466 @snapcraft.route("/community") 

467 def community_redirect(): 

468 return flask.redirect("/") 

469 

470 @snapcraft.route("/create") 

471 def create_redirect(): 

472 return flask.redirect("https://docs.snapcraft.io/build-snaps") 

473 

474 @snapcraft.route("/build") 

475 def build(): 

476 status_code = 200 

477 

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

479 

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

481 def sitemap(): 

482 xml_sitemap = flask.render_template( 

483 "sitemap/sitemap-index.xml", 

484 base_url="https://snapcraft.io", 

485 ) 

486 response = flask.make_response(xml_sitemap) 

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

488 

489 return response 

490 

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

492 def sitemap_links(): 

493 base_url = "https://snapcraft.io" 

494 links = [ 

495 {"url": f"{base_url}/about"}, 

496 {"url": f"{base_url}/about/publish"}, 

497 {"url": f"{base_url}/about/listing"}, 

498 {"url": f"{base_url}/about/release"}, 

499 {"url": f"{base_url}/about/publicise"}, 

500 {"url": f"{base_url}/iot"}, 

501 ] 

502 

503 xml_sitemap = flask.render_template( 

504 "sitemap/sitemap.xml", 

505 base_url="https://snapcraft.io", 

506 links=links, 

507 ) 

508 response = flask.make_response(xml_sitemap) 

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

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

511 

512 return response 

513 

514 return snapcraft