Coverage for webapp/admin/views.py: 70%

82 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2025-08-05 22:06 +0000

1# Packages 

2import os 

3import json 

4import flask 

5from flask import make_response 

6from canonicalwebteam.exceptions import ( 

7 StoreApiResponseErrorList, 

8) 

9from canonicalwebteam.store_api.dashboard import Dashboard 

10from canonicalwebteam.store_api.publishergw import PublisherGW 

11from canonicalwebteam.store_api.devicegw import DeviceGW 

12from flask.json import jsonify 

13 

14# Local 

15from webapp.decorators import login_required, exchange_required 

16from webapp.helpers import api_publisher_session, api_session 

17 

18 

19dashboard = Dashboard(api_session) 

20publisher_gateway = PublisherGW("snap", api_publisher_session) 

21device_gateway = DeviceGW("snap", api_session) 

22 

23admin = flask.Blueprint( 

24 "admin", __name__, template_folder="/templates", static_folder="/static" 

25) 

26 

27SNAPSTORE_DASHBOARD_API_URL = os.getenv( 

28 "SNAPSTORE_DASHBOARD_API_URL", "https://dashboard.snapcraft.io/" 

29) 

30 

31context = {"api_url": SNAPSTORE_DASHBOARD_API_URL} 

32 

33 

34def get_brand_id(session, store_id): 

35 store = dashboard.get_store(session, store_id) 

36 return store["brand-id"] 

37 

38 

39@admin.route("/admin", defaults={"path": ""}) 

40@admin.route("/admin/<path:path>") 

41@login_required 

42@exchange_required 

43def get_admin(path): 

44 return flask.render_template("admin/admin.html", **context) 

45 

46 

47@admin.route("/api/store/<store_id>/invite", methods=["POST"]) 

48@login_required 

49@exchange_required 

50def post_invite_members(store_id): 

51 members = json.loads(flask.request.form.get("members")) 

52 

53 res = {} 

54 

55 try: 

56 dashboard.invite_store_members(flask.session, store_id, members) 

57 res["msg"] = "Changes saved" 

58 except StoreApiResponseErrorList as api_response_error_list: 

59 msgs = [ 

60 f"{error.get('message', 'An error occurred')}" 

61 for error in api_response_error_list.errors 

62 ] 

63 

64 msgs = list(dict.fromkeys(msgs)) 

65 

66 for msg in msgs: 

67 flask.flash(msg, "negative") 

68 

69 return jsonify(res) 

70 

71 

72@admin.route("/api/store/<store_id>/invite/update", methods=["POST"]) 

73@login_required 

74@exchange_required 

75def update_invite_status(store_id): 

76 invites = json.loads(flask.request.form.get("invites")) 

77 

78 res = {} 

79 

80 try: 

81 dashboard.update_store_invites(flask.session, store_id, invites) 

82 res["msg"] = "Changes saved" 

83 except StoreApiResponseErrorList as api_response_error_list: 

84 msgs = [ 

85 f"{error.get('message', 'An error occurred')}" 

86 for error in api_response_error_list.errors 

87 ] 

88 

89 msgs = list(dict.fromkeys(msgs)) 

90 

91 for msg in msgs: 

92 flask.flash(msg, "negative") 

93 

94 return jsonify(res) 

95 

96 

97# -------------------- FEATURED SNAPS AUTOMATION ------------------ 

98@admin.route("/admin/featured", methods=["POST"]) 

99@login_required 

100@exchange_required 

101def post_featured_snaps(): 

102 """ 

103 In this view, we do three things: 

104 1. Fetch all currently featured snaps 

105 2. Delete the currently featured snaps 

106 3. Update featured snaps to be newly featured 

107 

108 Args: 

109 None 

110 

111 Returns: 

112 dict: A dictionary containing the response message and success status. 

113 """ 

114 

115 # new_featured_snaps is the list of featured snaps to be updated 

116 featured_snaps = flask.request.form.get("snaps") 

117 

118 if not featured_snaps: 

119 response = { 

120 "success": False, 

121 "message": "Snaps cannot be empty", 

122 } 

123 return make_response(response, 500) 

124 new_featured_snaps = featured_snaps.split(",") 

125 

126 # currently_featured_snap is the list of featured snaps to be deleted 

127 currently_featured_snaps = [] 

128 

129 next = True 

130 while next: 

131 featured_snaps = device_gateway.get_featured_snaps() 

132 currently_featured_snaps.extend( 

133 featured_snaps.get("_embedded", {}).get("clickindex:package", []) 

134 ) 

135 next = featured_snaps.get("_links", {}).get("next", False) 

136 

137 currently_featured_snap_ids = [ 

138 snap["snap_id"] for snap in currently_featured_snaps 

139 ] 

140 

141 delete_response = publisher_gateway.delete_featured_snaps( 

142 flask.session, {"packages": currently_featured_snap_ids} 

143 ) 

144 if delete_response.status_code != 201: 

145 response = { 

146 "success": False, 

147 "message": "An error occurred while deleting featured snaps", 

148 } 

149 return make_response(response, 500) 

150 snap_ids = [ 

151 dashboard.get_snap_id(flask.session, snap_name) 

152 for snap_name in new_featured_snaps 

153 ] 

154 

155 update_response = publisher_gateway.update_featured_snaps( 

156 flask.session, snap_ids 

157 ) 

158 if update_response.status_code != 201: 

159 response = { 

160 "success": False, 

161 "message": "An error occured while updating featured snaps", 

162 } 

163 return make_response(response, 500) 

164 return make_response({"success": True}, 200)