/
WebPortal+Email+Log.mm
303 lines (230 loc) · 12.2 KB
/
WebPortal+Email+Log.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/*=========================================================================
Program: OsiriX
Copyright (c) OsiriX Team
All rights reserved.
Distributed under GNU - LGPL
See http://www.osirix-viewer.com/copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
=========================================================================*/
#import "WebPortal+Email+Log.h"
#import "WebPortalDatabase.h"
#import "WebPortalResponse.h"
#import "NSUserDefaults+OsiriX.h"
#import "NSString+N2.h"
#import "NSMutableString+N2.h"
#import "WebPortalUser.h"
#import "DicomStudy.h"
#import "CSMailMailClient.h"
#import "DicomDatabase.h"
#import "AppController.h"
#import "NSManagedObject+N2.h"
#import "N2Debug.h"
// TODO: NSUserDefaults access for keys @"logWebServer", @"notificationsEmailsSender" and @"lastNotificationsDate" must be replaced with WebPortal properties
@implementation WebPortal (EmailLog)
- (void) sendEmailOnMainThread: (NSDictionary*) dict
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *ts = [dict objectForKey: @"template"];
NSDictionary *messageHeaders = [dict objectForKey: @"headers"];
[[CSMailMailClient mailClient] deliverMessage:ts headers:messageHeaders];
[pool release];
}
-(BOOL)sendNotificationsEmailsTo:(NSArray*)users aboutStudies:(NSArray*)filteredStudies predicate:(NSString*)predicate customText:(NSString*)customText
{
return [self sendNotificationsEmailsTo: users aboutStudies: filteredStudies predicate: predicate customText: customText from: nil];
}
-(BOOL)sendNotificationsEmailsTo:(NSArray*)users aboutStudies:(NSArray*)filteredStudies predicate:(NSString*)predicate customText:(NSString*)customText from:(WebPortalUser*) from
{
NSString *fromEmailAddress = [[NSUserDefaults standardUserDefaults] valueForKey: @"notificationsEmailsSender"];
if (fromEmailAddress == nil)
fromEmailAddress = @"";
for (WebPortalUser* user in users) {
NSMutableDictionary* tokens = [NSMutableDictionary dictionary];
if (customText) [tokens setObject:customText forKey:@"customText"];
[tokens setObject:user forKey:@"Destination"];
if( from)
[tokens setObject:from forKey:@"FromUser"];
[tokens setObject:self.URL forKey:@"WebServerURL"];
[tokens setObject:filteredStudies forKey:@"Studies"];
if (predicate) [tokens setObject:predicate forKey:@"predicate"];
NSMutableString* ts = [[[self stringForPath:@"emailTemplate.html"] mutableCopy] autorelease];
[WebPortalResponse mutableString:ts evaluateTokensWithDictionary:tokens context:NULL];
NSString* emailSubject = NSLocalizedString(@"A new radiology exam is available for you", nil);
NSMutableDictionary* messageHeaders = [NSMutableDictionary dictionary];
[messageHeaders setObject:user.email forKey:@"To"];
[messageHeaders setObject:fromEmailAddress forKey:@"Sender"];
[messageHeaders setObject:emailSubject forKey:@"Subject"];
// NSAttributedString initWithHTML is NOT thread-safe
[self performSelectorOnMainThread: @selector(sendEmailOnMainThread:) withObject: [NSDictionary dictionaryWithObjectsAndKeys: ts, @"template", messageHeaders, @"headers", nil] waitUntilDone: NO];
for (NSManagedObject* s in filteredStudies)
[self updateLogEntryForStudy:s withMessage: @"notification email" forUser:user.name ip:nil];
}
return YES; // succeeded
}
// TEMPORARY USERS
- (void) deleteTemporaryUsers:(NSTimer*)timer
{
[database.managedObjectContext lock];
@try
{
BOOL toBeSaved = NO;
NSArray *users = [database objectsForEntity:database.userEntity];
for (WebPortalUser* user in users)
{
if (user.autoDelete.boolValue == YES && user.deletionDate && [user.deletionDate timeIntervalSinceNow] < 0)
{
NSLog( @"----- Temporary User reached the EOL (end-of-life) : %@", user.name);
[self updateLogEntryForStudy:nil withMessage: @"temporary user deleted" forUser:user.name ip:nil];
toBeSaved = YES;
[database.managedObjectContext deleteObject:user];
}
}
if (toBeSaved)
[database save:NULL];
}
@catch (NSException *e)
{
NSLog( @"***** deleteTemporaryUsers exception for deleting temporary users: %@", e);
}
[database.managedObjectContext unlock];
}
- (void) emailNotifications
{
if ([NSThread isMainThread] == NO)
{
NSLog( @"********* emailNotifications: applescript needs to be in the main thread");
return;
}
if( [[NSUserDefaults standardUserDefaults] boolForKey: @"passwordWebServer"] == NO)
return;
// Lets check if new studies are available for each users! and if temporary users reached the end of their life.....
NSDate *lastCheckDate = [NSDate dateWithTimeIntervalSinceReferenceDate: [[NSUserDefaults standardUserDefaults] doubleForKey: @"lastNotificationsDate"]];
NSString *newCheckString = [NSString stringWithFormat: @"%lf", [NSDate timeIntervalSinceReferenceDate]];
if ([[NSUserDefaults standardUserDefaults] objectForKey: @"lastNotificationsDate"] == nil)
{
[[NSUserDefaults standardUserDefaults] setValue: [NSString stringWithFormat: @"%lf", [NSDate timeIntervalSinceReferenceDate]] forKey: @"lastNotificationsDate"];
return;
}
[database.managedObjectContext lock];
// CHECK dateAdded
if (self.notificationsEnabled)
{
@try
{
// Find all studies AFTER the lastCheckDate
NSArray *studies = [dicomDatabase objectsForEntity:@"Study"];
if ([studies count] > 0)
{
NSArray *users = [database objectsForEntity:database.userEntity];
for (WebPortalUser* user in users)
{
if ([[user valueForKey: @"emailNotification"] boolValue] == YES && [(NSString*) [user valueForKey: @"email"] length] > 2)
{
NSArray *filteredStudies = studies;
@try
{
filteredStudies = [studies filteredArrayUsingPredicate: [DicomDatabase predicateForSmartAlbumFilter: [user valueForKey: @"studyPredicate"]]];
if( user.studyPredicate.length)
filteredStudies = [user arrayByAddingSpecificStudiesToArray: filteredStudies];
filteredStudies = [filteredStudies filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"dateAdded > CAST(%lf, \"NSDate\")", [lastCheckDate timeIntervalSinceReferenceDate]]];
filteredStudies = [filteredStudies sortedArrayUsingDescriptors: [NSArray arrayWithObject: [[[NSSortDescriptor alloc] initWithKey: @"date" ascending:NO] autorelease]]];
}
@catch (NSException * e)
{
NSLog( @"******* studyPredicate exception : %@ %@", e, user);
}
if ([filteredStudies count] > 0)
{
[self sendNotificationsEmailsTo: [NSArray arrayWithObject: user] aboutStudies:[dicomDatabase objectsWithIDs:filteredStudies] predicate: [NSString stringWithFormat: @"browse=newAddedStudies&browseParameter=%lf", [lastCheckDate timeIntervalSinceReferenceDate]] customText: nil];
}
}
}
}
}
@catch (NSException *e)
{
NSLog( @"***** emailNotifications exception: %@", e);
}
}
[database.managedObjectContext unlock];
[[NSUserDefaults standardUserDefaults] setValue: newCheckString forKey: @"lastNotificationsDate"];
}
-(void)updateLogEntryForStudy:(DicomStudy*)study withMessage:(NSString*)message forUser:(NSString*)user ip:(NSString*)ip
{
if ([[NSUserDefaults standardUserDefaults] boolForKey: @"logWebServer"] == NO) return;
DicomDatabase* independentDatabase = nil;
if( [NSThread isMainThread])
independentDatabase = self.dicomDatabase;
else
independentDatabase = self.dicomDatabase.independentDatabase;
@try {
if (user)
message = [user stringByAppendingFormat:@": %@", message];
if (!ip)
ip = [[AppController sharedAppController] privateIP];
// Search for same log entry during last 5 min
NSArray* logs = NULL;
NSPredicate* predicate = [NSPredicate predicateWithFormat: @"(patientName==%@) AND (studyName==%@) AND (message==%@) AND (originName==%@) AND (endTime >= CAST(%lf, \"NSDate\"))", study.name, study.studyName, message, ip, [[NSDate dateWithTimeIntervalSinceNow: -5 * 60] timeIntervalSinceReferenceDate]];
logs = [independentDatabase objectsForEntity:independentDatabase.logEntryEntity predicate:predicate];
if (!logs.count) {
NSManagedObject* logEntry = [independentDatabase newObjectForEntity:independentDatabase.logEntryEntity];
[logEntry setValue:[NSDate date] forKey:@"startTime"];
[logEntry setValue:[NSDate date] forKey:@"endTime"];
[logEntry setValue:@"Web" forKey:@"type"];
if (study) {
[logEntry setValue:study.name forKey:@"patientName"];
[logEntry setValue:study.studyName forKey:@"studyName"];
}
[logEntry setValue:message forKey:@"message"];
if (ip)
[logEntry setValue:ip forKey:@"originName"];
} else
[logs setValue: [NSDate date] forKey: @"endTime"];
} @catch (NSException* e) {
NSLog( @"****** OsiriX HTTPConnection updateLogEntry exception : %@", e);
} @finally {
[independentDatabase save];
}
}
-(WebPortalUser*)newUserWithEmail:(NSString*)email
{
// create user
//NSArray* users = [self usersWithPredicate:[NSPredicate predicateWithFormat:@"email ==[cd] %@", email]];
//if (users.count)
// [NSException raise:NSGenericException format:NSLocalizedString(@"A user with email %@ already exists.", NULL), email];
if (![email isEmail])
[NSException raise:NSGenericException format:NSLocalizedString(@"%@ is not an email address.", NULL), email];
NSArray *existingUsers = [self.database.independentDatabase usersWithPredicate:[NSPredicate predicateWithFormat:@"email == %@", email]];
WebPortalUser* user = nil;
if( existingUsers.count)
user = [existingUsers objectAtIndex: 0];
else
{
user = [self.database.independentDatabase newUser];
user.email = email;
user.name = [email substringToIndex:[email rangeOfString:@"@"].location];
for (int i = 1; ![user validateForInsert:nil]; ++i)
user.name = [[email substringToIndex:[email rangeOfString:@"@"].location] stringByAppendingFormat:@"-%d", i];
user.autoDelete = [NSNumber numberWithBool:YES];
// send message
NSMutableDictionary* tokens = [NSMutableDictionary dictionary];
[tokens setObject:user forKey:@"User"];
[tokens setObject:self.URL forKey:@"WebServerURL"];
NSMutableString* ts = [[[self stringForPath:@"tempUserEmail.html"] mutableCopy] autorelease];
[WebPortalResponse mutableString:ts evaluateTokensWithDictionary:tokens context:NULL];
NSString* emailSubject = [NSString stringWithFormat:NSLocalizedString(@"Temporary account on %@", nil), self.URL];
NSMutableDictionary* messageHeaders = [NSMutableDictionary dictionary];
[messageHeaders setObject:user.email forKey:@"To"];
if( [[NSUserDefaults standardUserDefaults] valueForKey: @"notificationsEmailsSender"])
[messageHeaders setObject:[[NSUserDefaults standardUserDefaults] valueForKey: @"notificationsEmailsSender"] forKey:@"Sender"];
else
[messageHeaders setObject: @"" forKey:@"Sender"];
[messageHeaders setObject:emailSubject forKey:@"Subject"];
// NSAttributedString initWithHTML is NOT thread-safe
[self performSelectorOnMainThread: @selector(sendEmailOnMainThread:) withObject: [NSDictionary dictionaryWithObjectsAndKeys: ts, @"template", messageHeaders, @"headers", nil] waitUntilDone: NO];
}
return user;
}
@end