Coverage for webapp/template_utils.py: 97%

67 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-28 22:05 +0000

1# Core 

2import hashlib 

3import os 

4 

5from dateutil import parser 

6 

7from emoji import replace_emoji 

8 

9 

10# generator functions for templates 

11def generate_slug(path): 

12 """ 

13 Generate a slug for each page 

14 """ 

15 if path.endswith( 

16 ( 

17 "/snaps", 

18 "/listing", 

19 "/releases", 

20 "/metrics", 

21 "/publicise", 

22 "/publicise/badges", 

23 "/publicise/cards", 

24 "/settings", 

25 "/account/details", 

26 ) 

27 ): 

28 return "account" 

29 

30 if path == "/" or path.startswith("/first-snap"): 

31 return "home" 

32 

33 if path.startswith("/build"): 

34 return "build" 

35 

36 if path.startswith("/blog"): 

37 return "blog" 

38 

39 if path.startswith("/iot"): 

40 return "iot" 

41 

42 if path.startswith("/docs/snap-tutorials"): 

43 return "tutorials" 

44 

45 if path.startswith("/docs"): 

46 return "docs" 

47 

48 return "store" 

49 

50 

51# template filters 

52def contains(arr, contents): 

53 """ 

54 Template helper for detecting if an array contains an item 

55 """ 

56 

57 return contents in arr 

58 

59 

60def join(arr, separator=""): 

61 """ 

62 Template helper for joining array items into a string, using a separator 

63 """ 

64 

65 return separator.join(arr) 

66 

67 

68def static_url(filename): 

69 """ 

70 Template function for generating URLs to static assets: 

71 Given the path for a static file, output a url path 

72 with a hex hash as a query string for versioning 

73 """ 

74 

75 filepath = os.path.join("static", filename) 

76 url = "/" + filepath 

77 

78 if not os.path.isfile(filepath): 

79 # Could not find static file 

80 return url 

81 

82 # Use MD5 as we care about speed a lot 

83 # and not security in this case 

84 file_hash = hashlib.md5() 

85 with open(filepath, "rb") as file_contents: 

86 for chunk in iter(lambda: file_contents.read(4096), b""): 

87 file_hash.update(chunk) 

88 

89 return url + "?v=" + file_hash.hexdigest()[:7] 

90 

91 

92def install_snippet( 

93 package_name, default_track, lowest_risk_available, confinement 

94): 

95 """ 

96 Template function that returns the snippet value to 

97 install a snap to be used in distro pages and/or snap 

98 detail pages 

99 """ 

100 

101 snippet_value = "sudo snap install " + package_name 

102 

103 if lowest_risk_available != "stable": 

104 snippet_value += f" --{lowest_risk_available}" 

105 

106 if confinement == "classic": 

107 snippet_value += " --classic" 

108 

109 return snippet_value 

110 

111 

112def format_number(number: int): 

113 """ 

114 Template function that transforms a int into a string 

115 with a comma between every thousands 

116 """ 

117 return "{:,}".format(number) 

118 

119 

120def format_display_name(display_name): 

121 """Template function that formats the displayed name 

122 primarily to remove emoji 

123 """ 

124 return replace_emoji(display_name, replace="") 

125 

126 

127def display_name(display_name, username): 

128 """Template function that returns the displayed name if the username 

129 is the same, or the dispayed name and the username if differents 

130 """ 

131 display_name = format_display_name(display_name) 

132 if display_name.lower() == username.lower(): 

133 return display_name 

134 else: 

135 return f"{display_name} ({username})" 

136 

137 

138def format_date(timestamp, format): 

139 """Template function that returns a formatted date 

140 based on the given timestamp 

141 """ 

142 datestring = parser.parse(timestamp) 

143 

144 return datestring.strftime(format) 

145 

146 

147def format_member_role(role): 

148 """Template function that returns the 

149 correct label for a members role 

150 """ 

151 roles = { 

152 "admin": "admin", 

153 "review": "reviewer", 

154 "view": "viewer", 

155 "access": "publisher", 

156 } 

157 

158 return roles[role] 

159 

160 

161def format_link(url): 

162 """ 

163 Template function that removes protocol, path and query string from links 

164 """ 

165 url_parts = url.split(":") 

166 

167 if url_parts[0] == "mailto": 

168 return url_parts[1] 

169 

170 if url_parts[0] == "http" or url_parts[0] == "https": 

171 url_parts_no_slashes = url_parts[1].split("//")[1] 

172 url_parts_no_query = url_parts_no_slashes.split("?")[0] 

173 url_parts_no_path = url_parts_no_query.split("/")[0] 

174 

175 if url_parts_no_path in [ 

176 "github.com", 

177 "gitlab.com", 

178 "bitbucket.org", 

179 "launchpad.net", 

180 "sourceforge.net", 

181 ]: 

182 return url_parts_no_query 

183 

184 return url_parts_no_path