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
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-25 22:09 +0000
1import flask
3from webapp.config import DEFAULT_ICON_URL
4from webapp.llms import BASE_URL, store_llm
5from webapp.snapcraft import logic
8def snapcraft_blueprint():
9 snapcraft = flask.Blueprint("snapcraft", __name__)
11 @snapcraft.route("/")
12 def homepage():
13 nps = flask.request.args.get("nps")
15 livestream = logic.get_livestreams()
17 return flask.render_template(
18 "index.html", nps=nps, livestream=livestream
19 )
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
29 if "publisher" in flask.session:
30 publisher = flask.session["publisher"]
32 response = {"publisher": publisher}
33 response = flask.make_response(response)
35 # Unset the last_login_method cookie to avoid forcing
36 response.set_cookie("last_login_method", "", expires=0)
38 response.headers["Cache-Control"] = "no-store"
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
47 @snapcraft.route("/iot")
48 def iot():
49 status_code = 200
51 icon_host = "https://dashboard.snapcraft.io/site_media/appmedia"
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 ]
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 ]
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 ]
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 ]
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 ]
403 context = {
404 "devices": devices,
405 "robotics": robotics,
406 "smart_home": smart_home,
407 "networking": networking,
408 "board_images": board_images,
409 }
411 return (
412 flask.render_template("store/categories/iot.html", **context),
413 status_code,
414 )
416 @snapcraft.route("/about")
417 def about():
418 return flask.render_template("about/index.html")
420 @snapcraft.route("/about/publish")
421 def about_publish():
422 return flask.render_template("about/publish.html")
424 @snapcraft.route("/about/listing")
425 def about_listing():
426 return flask.render_template("about/listing.html")
428 @snapcraft.route("/about/release")
429 def about_release():
430 return flask.render_template("about/release.html")
432 @snapcraft.route("/about/publicise")
433 def about_publicise():
434 return flask.render_template("about/publicise.html")
436 @snapcraft.route("/about/contact-us")
437 def about_contact():
438 return flask.render_template("contact-us.html")
440 @snapcraft.route("/about/thank-you")
441 def about_thankyou():
442 return flask.render_template("thank-you.html")
444 @snapcraft.route("/community")
445 def community_redirect():
446 return flask.redirect("/")
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 )
456 @snapcraft.route("/build")
457 def build():
458 status_code = 200
460 return flask.render_template("snapcraft/build.html"), status_code
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"
471 return response
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 ]
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"
488 return response
490 return snapcraft