1
- '''
1
+ """
2
2
Contains the function that triggers whenever an app is published
3
3
to one of the streams that is set as an approval stream in
4
4
the QMC with a custom property='True' defined in the config.
5
5
6
6
Fires an email off to the associated addresses to any stream(s).
7
- '''
7
+ """
8
8
9
9
import logging
10
10
from logging .handlers import RotatingFileHandler
13
13
import json
14
14
import csv
15
15
from pathlib import Path
16
+ import base64
16
17
import Modules .qrs_functions as qrs
17
18
18
19
# configuration file
19
- with open ("config.json" ) as f :
20
+ with open ("static/ config.json" ) as f :
20
21
CONFIG = json .load (f )
21
22
f .close ()
22
23
23
24
# logging
24
- LOG_LEVEL = CONFIG ["log_level" ].lower ()
25
+ LOG_LEVEL = CONFIG ["logging" ][ " log_level" ].lower ()
25
26
26
- LOG_LOCATION = os .path .expandvars ("%ProgramData%\\ Qlik\\ Sense\\ Log" ) + \
27
- "\\ qs-event-driven-cross-site-app-promoter\\ "
27
+ # LOG_LOCATION = (
28
+ # os.path.expandvars("%ProgramData%\\Qlik\\Sense\\Log")
29
+ # + "\\qs-event-driven-cross-site-app-promoter\\"
30
+ # )
31
+
32
+ LOG_LOCATION = str (Path (__file__ ).parent .parent ).replace ("\\ " , "/" ) + "/Log/"
28
33
29
34
if not os .path .exists (LOG_LOCATION ):
30
35
os .makedirs (LOG_LOCATION )
31
36
32
37
LOG_FILE = LOG_LOCATION + "app_publish_review.log"
33
- if not os .path .isfile (LOG_FILE ):
34
- with open (LOG_FILE ,"w" ) as file :
35
- file .write ("{}\t {}\t {}\t {}\t {}\t {}\t {}\t {}" .format ("Timestamp" , "Module" ,
36
- "LogLevel" ,"Process" , "Thread" , "Status" , "LogID" , "Message" ))
37
- file .write ('\n ' )
38
- file .close ()
38
+ LOG_BYTES = int (CONFIG ["logging" ]["other_logs_bytes" ])
39
+ LOG_ROLLING_BACKUP = int (CONFIG ["logging" ]["other_logs_rolling_backup_num" ])
39
40
40
41
LOGGER = logging .getLogger (__name__ )
41
- # rolling logs with max 2 MB files with 3 backups
42
42
HANDLER = logging .handlers .RotatingFileHandler (
43
- LOG_FILE , maxBytes = 2000000 , backupCount = 3 )
43
+ LOG_FILE , maxBytes = LOG_BYTES , backupCount = LOG_ROLLING_BACKUP
44
+ )
44
45
45
46
if LOG_LEVEL == "info" :
46
47
logging .basicConfig (level = logging .INFO )
49
50
50
51
LOG_ID = str (uuid .uuid4 ())
51
52
APP_CHANGE_STATUS = "Initializing"
52
- FORMATTER = logging .Formatter ("%(asctime)s\t %(name)s\t %(levelname)s\t " +
53
- "%(process)d\t %(thread)d\t " + APP_CHANGE_STATUS + "\t %(message)s" )
53
+ FORMATTER = logging .Formatter (
54
+ "%(asctime)s\t %(name)s\t %(levelname)s\t "
55
+ + "%(process)d\t %(thread)d\t "
56
+ + APP_CHANGE_STATUS
57
+ + "\t %(message)s"
58
+ )
54
59
HANDLER .setFormatter (FORMATTER )
55
60
LOGGER .addHandler (HANDLER )
56
61
57
62
# additional config
58
63
PROMOTION_EMAIL_ALERTS = CONFIG ["promote_on_custom_property_change" ]["email_config" ][
59
- "promotion_email_alerts" ]
60
- CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH = CONFIG ["promote_on_custom_property_change" ][
61
- "email_config" ]["custom_property_name_stream_alert_on_publish" ]
62
- LOCAL_SERVER_FQDN = CONFIG [
63
- 'promote_on_custom_property_change' ]['local_server_FQDN' ]
64
+ "promotion_email_alerts"
65
+ ]
66
+ CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH = CONFIG [
67
+ "promote_on_custom_property_change"
68
+ ]["email_config" ]["custom_property_name_stream_alert_on_publish" ]
69
+ LOCAL_SERVER_FQDN = CONFIG ["promote_on_custom_property_change" ]["local_server_FQDN" ]
64
70
PROMOTION_SENDER_EMAIL = CONFIG ["promote_on_custom_property_change" ]["email_config" ][
65
- "promotion_sender_email" ]
71
+ "promotion_sender_email"
72
+ ]
66
73
PROMOTION_SENDER_PASS = CONFIG ["promote_on_custom_property_change" ]["email_config" ][
67
- "promotion_sender_pass" ]
74
+ "promotion_sender_pass"
75
+ ]
76
+ PROMOTION_SENDER_PASS_DECRYPTED = base64 .b64decode (PROMOTION_SENDER_PASS ).decode (
77
+ "utf-8"
78
+ )
68
79
PROMOTION_SMTP = CONFIG ["promote_on_custom_property_change" ]["email_config" ][
69
- "promotion_SMTP" ]
70
- PROMOTION_SMTP_PORT = CONFIG ["promote_on_custom_property_change" ][
71
- "email_config" ]["promotion_SMTP_port" ]
80
+ "promotion_SMTP"
81
+ ]
82
+ PROMOTION_SMTP_PORT = CONFIG ["promote_on_custom_property_change" ]["email_config" ][
83
+ "promotion_SMTP_port"
84
+ ]
72
85
73
86
# email alert config for app promotion
74
87
EMAIL_ALERTS = False
75
88
if PROMOTION_EMAIL_ALERTS .lower () == "true" :
76
89
try :
77
90
import smtplib
91
+
78
92
EMAIL_ALERTS = True
79
93
80
94
except Exception as error :
81
95
LOGGER .error (
82
- "%s\t Something went wrong while trying to setup email alerts: %s" , LOG_ID , error )
96
+ "%s\t Something went wrong while trying to setup email alerts: %s" ,
97
+ LOG_ID ,
98
+ error ,
99
+ )
83
100
else :
84
101
EMAIL_ALERTS = False
85
102
86
- APP_CHANGE_STATUS = "app_published_gather_info"
87
- FORMATTER = logging .Formatter ("%(asctime)s\t %(name)s\t %(levelname)s\t " +
88
- "%(process)d\t %(thread)d\t " + APP_CHANGE_STATUS + "\t %(message)s" )
89
- HANDLER .setFormatter (FORMATTER )
90
- LOGGER .addHandler (HANDLER )
91
-
92
103
93
104
def email_on_publish_to_review (app_id ):
94
- '''
105
+ """
95
106
Fires emails off to the addresses associated
96
107
with the streams designated as approval streams
97
108
once an app is published to one of them
98
- '''
99
- if EMAIL_ALERTS :
100
- log_id = str (uuid .uuid4 ())
109
+ """
110
+ app_change_status = "app_published_gather_info"
111
+ formatter = logging .Formatter (
112
+ "%(asctime)s\t %(name)s\t %(levelname)s\t "
113
+ + "%(process)d\t %(thread)d\t "
114
+ + app_change_status
115
+ + "\t %(message)s"
116
+ )
117
+ HANDLER .setFormatter (formatter )
118
+ LOGGER .addHandler (HANDLER )
119
+ log_id = str (uuid .uuid4 ())
101
120
121
+ if EMAIL_ALERTS :
102
122
s , base_url = qrs .establish_requests_session ("local" )
103
123
LOGGER .info ("%s\t Requesting app/full info on '%s'" , log_id , app_id )
104
124
app_full_status , app_full_response = qrs .app_full (s , base_url , app_id )
105
125
qrs .close_requests_session (s )
106
126
if app_full_status != 200 :
107
127
LOGGER .error (
108
- "%s\t Something went wrong while trying to get app/full: %s" , log_id , app_full_status )
128
+ "%s\t Something went wrong while trying to get app/full: %s" ,
129
+ log_id ,
130
+ app_full_status ,
131
+ )
109
132
else :
110
133
LOGGER .debug ("%s\t Got app/full data: %s" , log_id , app_full_status )
111
134
@@ -124,51 +147,71 @@ def email_on_publish_to_review(app_id):
124
147
LOGGER .info ("%s\t Published to stream Name: '%s'" , log_id , stream_name )
125
148
LOGGER .info ("%s\t Published to stream ID: '%s'" , log_id , stream_id )
126
149
127
- LOGGER .info ("%s\t Checking to see if the stream '%s' has the custom property '%s'" ,
128
- log_id , stream_id , CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH )
150
+ LOGGER .info (
151
+ "%s\t Checking to see if the stream '%s' has the custom property '%s'" ,
152
+ log_id ,
153
+ stream_id ,
154
+ CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH ,
155
+ )
129
156
130
157
s , base_url = qrs .establish_requests_session ("local" )
131
- LOGGER .info ("%s\t Requesting stream/full info on '%s'" ,
132
- log_id , stream_id )
158
+ LOGGER .info ("%s\t Requesting stream/full info on '%s'" , log_id , stream_id )
133
159
stream_full_status , stream_full_response = qrs .stream_full (
134
- s , base_url , stream_id )
160
+ s , base_url , stream_id
161
+ )
135
162
qrs .close_requests_session (s )
136
163
if stream_full_status != 200 :
137
- LOGGER .error ("%s\t Something went wrong while trying to get stream/full: %s" ,
138
- log_id , stream_full_status )
164
+ LOGGER .error (
165
+ "%s\t Something went wrong while trying to get stream/full: %s" ,
166
+ log_id ,
167
+ stream_full_status ,
168
+ )
139
169
else :
140
- LOGGER .debug ("%s\t Got stream/full data: %s" ,
141
- log_id , stream_full_status )
170
+ LOGGER .debug ("%s\t Got stream/full data: %s" , log_id , stream_full_status )
142
171
143
172
stream_custom_properties = stream_full_response ["customProperties" ]
144
- LOGGER .debug ("%s\t Stream custom properties: %s" ,
145
- log_id , stream_custom_properties )
173
+ LOGGER .debug (
174
+ "%s\t Stream custom properties: %s" , log_id , stream_custom_properties
175
+ )
146
176
147
177
stream_marked_for_approval = False
148
178
for stream_prop in stream_custom_properties :
149
- if stream_prop ["definition" ]["name" ] == CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH :
179
+ if (
180
+ stream_prop ["definition" ]["name" ]
181
+ == CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH
182
+ ):
150
183
stream_marked_for_approval = True
151
184
break
152
185
153
186
if stream_marked_for_approval :
154
187
app_change_status = "app_published_to_approval_stream"
155
- formatter = logging .Formatter ("%(asctime)s\t %(name)s\t %(levelname)s\t " +
156
- "%(process)d\t %(thread)d\t " + app_change_status + "\t %(message)s" )
188
+ formatter = logging .Formatter (
189
+ "%(asctime)s\t %(name)s\t %(levelname)s\t "
190
+ + "%(process)d\t %(thread)d\t "
191
+ + app_change_status
192
+ + "\t %(message)s"
193
+ )
157
194
HANDLER .setFormatter (formatter )
158
195
LOGGER .addHandler (HANDLER )
159
196
LOGGER .info (
160
- "%s\t App published to approval stream: '%s', configuring email" , log_id , stream_name )
197
+ "%s\t App published to approval stream: '%s', configuring email" ,
198
+ log_id ,
199
+ stream_name ,
200
+ )
161
201
162
202
try :
163
- EMAIL_MAP_FILE_DIRECTORY = str (
164
- Path (__file__ ).parent .parent ).replace ("\\ " , "/" )
165
- EMAIL_MAP_FILE = EMAIL_MAP_FILE_DIRECTORY + \
166
- '/ApprovalStreamsToEmailAddressMap.csv'
203
+ EMAIL_MAP_FILE_DIRECTORY = str (Path (__file__ ).parent .parent ).replace (
204
+ "\\ " , "/"
205
+ )
206
+ EMAIL_MAP_FILE = (
207
+ EMAIL_MAP_FILE_DIRECTORY
208
+ + "/static/ApprovalStreamsToEmailAddressMap.csv"
209
+ )
167
210
EMAIL_MAP_STREAM_LIST = []
168
211
EMAIL_MAP_ADDRESS_LIST = []
169
212
170
213
with open (EMAIL_MAP_FILE ) as email_map :
171
- reader = csv .reader (email_map , delimiter = ',' )
214
+ reader = csv .reader (email_map , delimiter = "," )
172
215
next (reader , None ) # skip the header
173
216
for row in reader :
174
217
EMAIL_MAP_STREAM_LIST .append (row [0 ])
@@ -182,35 +225,57 @@ def email_on_publish_to_review(app_id):
182
225
recipient_list = list (set (recipient_list ))
183
226
LOGGER .info ("%s\t Recipient list: '%s'" , log_id , recipient_list )
184
227
185
- subject = "'{}' published to: '{}'" .format (
186
- app_name , stream_name )
228
+ subject = "'{}' published to: '{}'" .format (app_name , stream_name )
187
229
body = """Application: '{}'\n Owned by: '{}'\n Published by: '{}'\n Published to: '{}'
188
230
\n \n View the app here: https://{}/sense/app/{}""" .format (
189
- app_name , app_owner , modified_by_user , stream_name , LOCAL_SERVER_FQDN , app_id )
190
- message = """From: %s\n To: %s\n Subject: %s\n \n %s""" % (PROMOTION_SENDER_EMAIL , ", " .join (
191
- recipient_list ), subject , body )
231
+ app_name ,
232
+ app_owner ,
233
+ modified_by_user ,
234
+ stream_name ,
235
+ LOCAL_SERVER_FQDN ,
236
+ app_id ,
237
+ )
238
+ message = """From: %s\n To: %s\n Subject: %s\n \n %s""" % (
239
+ PROMOTION_SENDER_EMAIL ,
240
+ ", " .join (recipient_list ),
241
+ subject ,
242
+ body ,
243
+ )
192
244
193
245
try :
194
246
server = smtplib .SMTP (PROMOTION_SMTP , PROMOTION_SMTP_PORT )
195
247
server .ehlo ()
196
248
server .starttls ()
197
- server .login (PROMOTION_SENDER_EMAIL , PROMOTION_SENDER_PASS )
198
- server .sendmail (PROMOTION_SENDER_EMAIL ,
199
- recipient_list , message )
249
+ server .login (
250
+ PROMOTION_SENDER_EMAIL , PROMOTION_SENDER_PASS_DECRYPTED
251
+ )
252
+ server .sendmail (PROMOTION_SENDER_EMAIL , recipient_list , message )
200
253
server .close ()
201
- LOGGER .info ("%s\t Successfully sent the email to %s" ,
202
- log_id , recipient_list )
254
+ LOGGER .info (
255
+ "%s\t Successfully sent the email to %s" , log_id , recipient_list
256
+ )
203
257
except Exception as error :
204
258
LOGGER .error (
205
- "%s\t There was an error trying to send the email %s" , log_id , error )
259
+ "%s\t There was an error trying to send the email %s" ,
260
+ log_id ,
261
+ error ,
262
+ )
206
263
207
264
except Exception as error :
208
265
LOGGER .error (
209
- "%s\t Something went wrong with the email alerts: %s" , log_id , error )
266
+ "%s\t Something went wrong with the email alerts: %s" , log_id , error
267
+ )
210
268
LOGGER .error (
211
- "%s\t Ensure you have filled out 'ApprovalStreamsToEmailAddressMap.csv' properly" , log_id )
269
+ "%s\t Ensure you have filled out 'ApprovalStreamsToEmailAddressMap.csv' properly" ,
270
+ log_id ,
271
+ )
212
272
else :
213
- LOGGER .info ("%s\t Stream '%s' with id '%s' does not contain the custom property '%s'. Exiting." ,
214
- log_id , stream_name , stream_id , CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH )
273
+ LOGGER .info (
274
+ "%s\t Stream '%s' with id '%s' does not contain the custom property '%s'. Exiting." ,
275
+ log_id ,
276
+ stream_name ,
277
+ stream_id ,
278
+ CUSTOM_PROPERTY_NAME_STREAM_ALERT_ON_PUBLISH ,
279
+ )
215
280
216
281
return "Finished"
0 commit comments