Coverage for webapp/app.py: 68%

84 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-27 22:07 +0000

1import talisker.requests 

2from flask import render_template, make_response, request, session 

3from dateutil import parser 

4 

5from canonicalwebteam.candid import CandidClient 

6from canonicalwebteam.flask_base.app import FlaskBase 

7 

8from webapp.store_api import publisher_gateway 

9from webapp.extensions import csrf 

10from webapp.config import APP_NAME 

11from webapp.handlers import set_handlers 

12from webapp.login.views import login 

13from webapp.topics.views import topics 

14from webapp.publisher.views import publisher 

15from webapp.store.views import store 

16from webapp.integrations.views import integrations 

17from webapp.search.views import search 

18from webapp.search.logic import cache 

19from webapp.helpers import markdown_to_html 

20from webapp.decorators import login_required 

21from webapp.packages.store_packages import store_packages 

22from opentelemetry.instrumentation.requests import RequestsInstrumentor 

23from opentelemetry.instrumentation.flask import FlaskInstrumentor 

24from opentelemetry.trace import Span 

25 

26 

27app = FlaskBase( 

28 __name__, 

29 "charmhub.io", 

30 template_404="404.html", 

31 template_500="500.html", 

32 favicon_url="https://assets.ubuntu.com/v1/5d4edefd-jaas-favicon.png", 

33 static_folder="../static", 

34 template_folder="../templates", 

35) 

36 

37 

38app.name = APP_NAME 

39app.config["LOGIN_REQUIRED"] = login_required 

40 

41set_handlers(app) 

42 

43request_session = talisker.requests.get_session() 

44candid = CandidClient(request_session) 

45cache.init_app(app) 

46csrf.init_app(app) 

47 

48app.register_blueprint(store_packages) 

49app.register_blueprint(publisher) 

50app.register_blueprint(store) 

51app.register_blueprint(login) 

52app.register_blueprint(topics) 

53app.register_blueprint(integrations) 

54app.register_blueprint(search) 

55 

56 

57app.jinja_env.filters["markdown"] = markdown_to_html 

58 

59# OpenTelemetry 

60UNTRACED_ROUTES = ["/_status", "/static", ".json"] 

61 

62 

63def request_hook(span: Span, environ): 

64 if span and span.is_recording(): 

65 span.update_name(f"{environ['REQUEST_METHOD']} {environ['PATH_INFO']}") 

66 

67 

68# Add tracing auto instrumentation 

69FlaskInstrumentor().instrument_app( 

70 app, excluded_urls=",".join(UNTRACED_ROUTES), request_hook=request_hook 

71) 

72RequestsInstrumentor().instrument() 

73 

74 

75@app.route("/account.json") 

76def get_account_json(): 

77 """ 

78 A JSON endpoint to request login status 

79 """ 

80 account = None 

81 

82 if "account" in session: 

83 account = session["account"] 

84 

85 response = {"account": account} 

86 response = make_response(response) 

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

88 

89 return response 

90 

91 

92@app.route("/contact-us") 

93def contact_us(): 

94 return render_template("contact-us.html") 

95 

96 

97@app.route("/thank-you") 

98def thank_you(): 

99 return render_template("thank-you.html") 

100 

101 

102@app.route("/icon-validator") 

103def icon_validator(): 

104 return render_template("icon-validator.html") 

105 

106 

107@app.route("/sitemap.xml") 

108def site_map(): 

109 xml_sitemap = render_template( 

110 "sitemap/sitemap.xml", 

111 base_url=f"{request.scheme}://{request.host}", 

112 ) 

113 response = make_response(xml_sitemap) 

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

115 

116 return response 

117 

118 

119@app.route("/sitemap-links.xml") 

120def site_map_links(): 

121 links = [ 

122 "/contact-us", 

123 ] 

124 

125 xml_sitemap = render_template( 

126 "sitemap/sitemap-links.xml", 

127 base_url=f"{request.scheme}://{request.host}", 

128 links=links, 

129 ) 

130 response = make_response(xml_sitemap) 

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

132 

133 return response 

134 

135 

136@app.route("/sitemap-operators.xml") 

137def site_map_operators(): 

138 charms = publisher_gateway.find( 

139 fields=["default-release.channel.released-at"] 

140 ).get("results", []) 

141 

142 for charm in charms: 

143 charm["date"] = ( 

144 parser.parse(charm["default-release"]["channel"]["released-at"]) 

145 .replace(tzinfo=None) 

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

147 ) 

148 

149 xml_sitemap = render_template( 

150 "sitemap/sitemap-operators.xml", 

151 base_url=f"{request.scheme}://{request.host}", 

152 charms=charms, 

153 ) 

154 response = make_response(xml_sitemap) 

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

156 

157 return response