Confirmation and reminder emails for experimental research in Matlab, as well as a script to send brain images to participants.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function confirmation_email(contactemail) | |
% CONFIRMATION_EMAIL | |
% Vanessa Sochat | |
% | |
% This script sends confirmation emails for imaging and battery appointments | |
% added to the calendar the previous day. | |
% | |
% ------------------------------------------------------------------------- | |
% VARIABLES: | |
% | |
% contactemail: An email address that you want to be notified in | |
% the case of error | |
% | |
% ------------------------------------------------------------------------- | |
% DEPENDENCY: | |
% For the script to work, it must have access to each of the appointment | |
% private calendars (URL's hard coded), and the data in the calendar must | |
% have the user email as the first thing in the Description field, like so | |
% | |
% Name: Jane Doe | |
% Phone: (999) 999-9999 | |
% E-mail: jane.doe@duke.edu | |
% | |
% poozie.mat must be in the same folder it is running from | |
% | |
% schedule.csv: Downloaded by the batch script just before running | |
% the matlab script - this file contains all subject specific info that is | |
% used to look up an individual based on name. | |
%-------------------------------------------------------------------------- | |
% OUTPUT: | |
% A log of confirmation email info is saved, and all files are located | |
% under: | |
% | |
% Y:/Scripts/Appointments | |
% ------------------------------------------------------------------------- | |
%-------------------------------------------------------------------------- | |
% Set up mail credentials | |
%-------------------------------------------------------------------------- | |
load poozie.mat | |
email_count=0; | |
% Path to the reminder and directions sheet | |
reminder_directions = 'Y:/Scripts/Appointments/Reminder_and_Directions.pdf'; | |
% Then this code will set up the preferences properly: | |
setpref('Internet','E_mail',poozie); | |
setpref('Internet','SMTP_Server','smtp.gmail.com'); | |
setpref('Internet','SMTP_Username',poozie); | |
setpref('Internet','SMTP_Password',pooziepa); | |
props = java.lang.System.getProperties; | |
props.setProperty('mail.smtp.auth','true'); | |
props.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory'); | |
props.setProperty('mail.smtp.socketFactory.port','465'); | |
%-------------------------------------------------------------------------- | |
% Read in appointment file (schedule.csv) downloaded from server | |
%-------------------------------------------------------------------------- | |
% If the file exists, read it in. If it doesn't, exit with an error, | |
% record error to the log, and email Vanessa about error. | |
if exist('schedule.csv','file') | |
fid = fopen('schedule.csv'); | |
else | |
% Initialize and print to file | |
fid = fopen('ERROR_LOG.txt', 'a'); | |
fprintf(fid, 'Date: '); | |
fprintf(fid,'%s\n', date'); | |
fprintf(fid, 'Schedule file does not exist! Check download.'); | |
fclose(fid); | |
% If the user has provided an email, alert that email of the failure: | |
if exist('contactemail','var') | |
sendmail(contactemail,'Message from Rem_Email.m',[ 'The script exited with error on ' date ' while sending out ' days ' day reminders for the ' calendar ' calendar. '],''); | |
end | |
error('Schedule file does not exist'); | |
end | |
% READ APPOINTMENT INFORMATION FROM FILE | |
% First read in the header fields | |
H = textscan(fid, '%s %s %s %s %s %s %s %s %s %s %s \n', 'delimiter', ','); | |
% StartTime {H1} | |
% EndTime (H2) | |
% First Name (H3) | |
% Last Name (H4) | |
% Phone (H5) | |
% Email (H6) | |
% Type (H7) | |
% Calendar (H8) | |
% Duke Unique ID (H9) | |
% Text Message? (H10) | |
% Phone Carrier (H11) | |
% Then read the data from the rest of the file | |
C = textscan(fid, '%s %s %s %s %s %s %s %s %s %s %s %s %s', 'delimiter', ','); | |
% StartDate {C1} | |
% StartTime (C2) | |
% EndDate (C3) | |
% EndTime (C4) | |
% First Name (C5) | |
% Last Name (C6) | |
% Phone (C7) | |
% Email (C8) | |
% Appointment Type (C9) | |
% Clinician (C10) | |
% Unique ID (C11) | |
% Text Message? (C12) | |
% Phone Carrier (C13) | |
% Now we convert a cell array into an array of strings so we can read each | |
% one, only for the fields that we are interested in. | |
FirstNames = C{5}; | |
LastNames = C{6}; | |
Phones = C{7}; | |
Emails = C{8}; | |
Txt = C{12}; | |
Carriers = C{13}; | |
fclose(fid); | |
clear C H fid; | |
%-------------------------------------------------------------------------- | |
% Download latest appointments from imaging and computer calendar to file | |
%-------------------------------------------------------------------------- | |
% CD to directory for saving current appointment files | |
cd('Y:/Scripts/Appointments/'); | |
% Download and save the calendar data, if it doesn't already exist in the | |
% folder (since the reminder emails are sent just before and haven't been | |
% deleted by the batch script, these files should already exist!) | |
if exist('imaging.txt','file')==0 | |
calie{1} = urlwrite(schmoogie,'imaging.txt','get',{}); | |
else | |
calie{1} = 'imaging.txt'; | |
end | |
meetingloc{1} = 'Soc-Psych 07'; | |
cal{1} = 'Imaging'; | |
if exist('computer.txt','file')==0 | |
calie{2} = urlwrite(yebya,'computer.txt','get',{}); | |
else | |
calie{2} = 'computer.txt'; | |
end | |
meetingloc{2} = 'LSRC B Lobby'; | |
cal{2} = 'Computer'; | |
%-------------------------------------------------------------------------- | |
% Read appointments from the file and save to variable | |
%-------------------------------------------------------------------------- | |
% Open the subject appointment file, which was an .ical file that we open as | |
% a text file | |
for v=1:2 | |
fln = fopen(calie{v}); | |
% Create a subject count variable | |
appt_count=0; | |
% Set the current appointment date to today, so we can stop reading the | |
% file when the appointments go into the past. | |
Appointment=date; | |
% Set today's date in a number format for easy comparison | |
today = datenum(date); | |
while ~feof(fln) | |
% We need to make sure that we only read in appointments for today and | |
% in the future, so we do a comparison between the current appointment | |
% that is being read. We use a do-->while loop so that the comparison | |
% until after a subject has been | |
% Read in line | |
currentline = fgetl(fln); | |
% Look to see if we have a date line, which starts with 'DSTART' | |
if regexp(currentline, 'DTSTART', 'once'); | |
%if yes, pull the date and time from this line, and format | |
year = currentline(9:12); | |
month = currentline(13:14); | |
day = currentline(15:16); | |
appointment = datestr([ year ' ' month ' ' day ]); | |
time = currentline(18:21); | |
time = str2double(time); | |
% The time is 4 hours in the future, so we subtract 4: | |
time = time - 400; | |
% Convert military time to standard time | |
if (time > 1259) | |
time = time-1200; | |
period = 'pm'; | |
else | |
if (time >= 1200) && (time <= 1259) | |
period = 'pm'; | |
else | |
period = 'am'; | |
end | |
end | |
% Format time with a ":" by separating the last two characters | |
% from the first, and sticking them together with a ":" | |
time = num2str(time); | |
time_end = time(length(time)-1:length(time)); | |
time_beg = regexprep(time, time_end, '','once'); | |
% Put it all together into a user friendly format for printing | |
time = [ time_beg ':' time_end ' ' period ]; | |
% If the appointment is from before today, we don't want to do | |
% anything. | |
if(today > datenum(appointment)) | |
else | |
%Add another subject to the array if they aren't from the past | |
appt_count = appt_count +1; | |
APPTS(appt_count)= struct('First','','Last','','Email', '','Phone','','Appointment', appointment, 'Time', time,'Text','','Carrier','','Created',''); | |
end | |
end | |
% Look to see if we have a date created line, which starts with 'CREATED' | |
if regexp(currentline, 'CREATED', 'once'); | |
%if yes, pull the date and time from this line, and format | |
create_year = currentline(9:12); | |
create_month = currentline(13:14); | |
create_day = currentline(15:16); | |
created = datestr([ create_year ' ' create_month ' ' create_day ]); | |
% If the appointment is from before today, we don't want to do | |
% anything. | |
if(today > datenum(appointment)) | |
else | |
APPTS(appt_count).Created = created; | |
end | |
end | |
% Look to see if we have a participant info line: | |
if regexp(currentline, 'DESCRIPTION', 'once'); | |
% Only read the line if there is data there, meaning the length | |
% is greater than 12 (the length of DESCRIPTION:) | |
if length(currentline) > 12 | |
% If the appointment is from the past, skip it, as we did | |
% above | |
if (today > datenum(appointment)) | |
else | |
%if yes, first get rid of the 'DESCRIPTION:Name: ' section | |
currentline = regexprep(currentline, currentline(1:18), '','once'); | |
% Put the first name into a variable by finding the end of it, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
name = currentline(1:marker-1); | |
currentline = regexprep(currentline, currentline(1:marker), '','once'); | |
% Put the last name into a variable by finding the end, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
lastname = currentline(1:marker-1); | |
% Add name to the data structure | |
APPTS(appt_count).First = deblank(name); | |
APPTS(appt_count).Last = deblank(lastname); | |
end | |
end | |
end | |
% Take in the name from the summary field, in case we need it | |
if regexp(currentline, 'SUMMARY', 'once'); | |
currentline = regexprep(currentline, currentline(1:8), '','once'); | |
% Put the first name into a variable by finding the end of it, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
name = currentline(1:marker-1); | |
currentline = regexprep(currentline, currentline(1:marker), '','once'); | |
% Put the last name into a variable by finding the end, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
if isempty(marker) | |
lastname = currentline; | |
else | |
lastname = currentline(1:marker-1); | |
end | |
% In the case that the name was not present in the | |
% DESCRIPTION, we can get it from the Summary! | |
if isempty(APPTS(appt_count).First) | |
APPTS(appt_count).First = deblank(name); | |
end | |
if isempty(APPTS(appt_count).Last) | |
APPTS(appt_count).Last = deblank(lastname); | |
end | |
end | |
end | |
%-------------------------------------------------------------------------- | |
% Find rest of subject info by reading from Appointment file | |
%-------------------------------------------------------------------------- | |
% Need to find a way to decrease search through appointment file! Right now | |
% we look at everyone and compare First and Last Name. Since the | |
% information on the calendar is equivalent to the online system, | |
% these fields should match for each subject. If we have duplicates, then | |
% Vanessa can add phone number matching to the script. We place the | |
% current first and last name in a deblanked variable instead of | |
% referencing them from the array each time so we can easily calculate the | |
% length without blank spaces. | |
for i=1:length(FirstNames) | |
for k=1:length(APPTS) | |
currentfirst = deblank(FirstNames{i}); | |
currentlast = deblank(LastNames{i}); | |
if length(APPTS(k).First) >= length(currentfirst) | |
if strcmp(currentfirst,deblank(APPTS(k).First(1:length(currentfirst)))) | |
if length(APPTS(k).Last) >= length(currentlast) | |
if strcmp(currentlast,deblank(APPTS(k).Last(1:length(currentlast)))) | |
APPTS(k).Phone = deblank(Phones{i}); | |
APPTS(k).Text = Txt{i}; | |
APPTS(k).Carrier = Carriers{i}; | |
APPTS(k).Email = deblank(Emails{i}); | |
end | |
end | |
end | |
end | |
end | |
end | |
clear currentfirst currentlast | |
%-------------------------------------------------------------------------- | |
% Send confirmation emails | |
%-------------------------------------------------------------------------- | |
% Cycle through the participants in the array, and if the appointment was | |
% made the previous day (since this script runs in the wee hours of the | |
% morning) we want to send a confirmation email with directions attached. | |
yesterday = today -1; | |
for i=1:size(APPTS,2) | |
if (datenum(APPTS(i).Created) == yesterday) | |
% ------------------------------------------------------------- | |
% FIRST SEND EMAIL | |
%-------------------------------------------------------------- | |
% If the subject has an email, we send a confirmation email | |
if isempty(APPTS(i).Email)==0 | |
sendmail(APPTS(i).Email,[ 'Laboratory of Neurogenetics - ' cal{v} ' Appointment Confirmation' ],[ APPTS(i).First ', this is a confirmation of your ' cal{v} ' session appointment on ' datestr(APPTS(i).Appointment,'mmm dd, yyyy') ' at ' APPTS(i).Time '. For your appointment, please meet the experimenter at ' meetingloc{v} '. Appointment details and directions are attached.' ],reminder_directions); | |
else | |
% We will want to know about this error, so we save the | |
% subject information to an array, to be emailed later. | |
APPT_ERRORS(email_count+1) = APPTS(i); | |
end | |
end | |
end | |
%-------------------------------------------------------------------------- | |
% Update sending log | |
%-------------------------------------------------------------------------- | |
% Initialize and print to file | |
lid = fopen('CONFIRMATION_LOG.txt', 'a'); | |
% List the headings if the file is just being created | |
if exist('CONFIRMATION_LOG.txt','file')==0 | |
fprintf(lid, 'Date,Calendar,Appt_Days_Away,First,Last,Email,Phone,Appointment,Time,Text,Carrier,'); | |
end | |
for i=1:numel(APPTS) | |
fprintf(lid,'\n%s', [ date ',' ]'); | |
fprintf(lid,'%s', [ cal{v} ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).First ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Last ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Email ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Phone ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Appointment ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Time ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Text ',' ]'); | |
fprintf(lid,'%s', APPTS(i).Carrier); | |
end | |
fclose(lid); | |
end | |
clear i Phones Txt Carriers Emails FirstNames LastNames | |
%-------------------------------------------------------------------------- | |
% Email to send if there are errors in reading the calendar or sending | |
% brains | |
%-------------------------------------------------------------------------- | |
if exist('APPT_ERRORS','var') | |
save('APPT_ERRORS','APPTS.mat'); | |
if exist('contactemail','var') | |
sendmail(contactemail,'Message from Rem_Email.m',[ 'The script had subjects with missing emails on ' date ' while sending out confirmation emails for the ' cal{v} ' calendar. The attached mat file contains these subjects!'],'APPTS.mat'); | |
end | |
end | |
% Exit from matlab to run the next script | |
exit | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function rem_email(days,cal,sendtxt,sendemail,contactemail) | |
% REM_EMAIL | |
% Vanessa Sochat | |
% | |
% This series of scripts can be run to download appointment data from the | |
% lab calendar and send reminder emails at the time specified. Emails | |
% sent are recorded | |
% | |
% ------------------------------------------------------------------------- | |
% VARIABLES: | |
% days: This is the number of days in advance that the reminder emails | |
% will be sent. (1 = 24 hrs, 2 = 48 hrs, etc) | |
% | |
% calendars: This is the calendar name that the reminders will be | |
% sent to, for each of the times indicated. This can currently be | |
% "Computer" or "Imaging." | |
% | |
% sendtxt: 'yes' indicates we want to send a text message, no means no! | |
% | |
% sendemail: 'yes' indicates we want to send an email, no means no! | |
% | |
% contactemail:(optional) An email address that you want to be notified in | |
% the case of error | |
% | |
% ------------------------------------------------------------------------- | |
% DEPENDENCY: | |
% For the script to work, it must have access to each of the appointment | |
% private calendars (URL's hard coded), and the data in the calendar must | |
% have the user email as the first thing in the Description field, like so | |
% | |
% Name: Jane Doe | |
% Phone: (999) 999-9999 | |
% E-mail: jane.doe@duke.edu | |
% | |
% poozie.mat must be in the same folder it is running from | |
% | |
% schedule.csv: Downloaded by the batch script just before running | |
% the matlab script - this file contains all subject specific info that is | |
% used to look up an individual based on name. | |
%-------------------------------------------------------------------------- | |
% OUTPUT: | |
% A temporary file of appointment info for each calendar is saved, but | |
% deleted when the script finishes running. A log is updated with emails | |
% that were successfully sent. All files are located under | |
% Y:/Scripts/Appointments | |
% ------------------------------------------------------------------------- | |
%-------------------------------------------------------------------------- | |
% Set up mail credentials | |
%-------------------------------------------------------------------------- | |
load poozie.mat | |
email_count=0; | |
% Path to the reminder and directions sheet | |
reminder_directions = 'Y:/Scripts/Appointments/Reminder_and_Directions.pdf'; | |
% Then this code will set up the preferences properly: | |
setpref('Internet','E_mail',poozie); | |
setpref('Internet','SMTP_Server','smtp.gmail.com'); | |
setpref('Internet','SMTP_Username',poozie); | |
setpref('Internet','SMTP_Password',pooziepa); | |
props = java.lang.System.getProperties; | |
props.setProperty('mail.smtp.auth','true'); | |
props.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory'); | |
props.setProperty('mail.smtp.socketFactory.port','465'); | |
%-------------------------------------------------------------------------- | |
% Read in appointment file (schedule.csv) downloaded from server | |
%-------------------------------------------------------------------------- | |
% If the file exists, read it in. If it doesn't, exit with an error, | |
% record error to the log, and email Vanessa about error. | |
if exist('schedule.csv','file') | |
fid = fopen('schedule.csv'); | |
else | |
% Initialize and print to file | |
fid = fopen('ERROR_LOG.txt', 'a'); | |
fprintf(fid, 'Date: '); | |
fprintf(fid,'%s\n', date'); | |
fprintf(fid, 'Schedule file does not exist! Check download.'); | |
fclose(fid); | |
% If the user has provided an email, alert that email of the failure: | |
if exist('contactemail','var') | |
sendmail(contactemail,'Message from Rem_Email.m',[ 'The script exited with error on ' date ' while sending out ' days ' day reminders for the ' calendar ' calendar. '],''); | |
end | |
error('Schedule file does not exist'); | |
end | |
% READ APPOINTMENT INFORMATION FROM FILE | |
% First read in the header fields | |
H = textscan(fid, '%s %s %s %s %s %s %s %s %s %s %s \n', 'delimiter', ','); | |
% StartTime {H1} | |
% EndTime (H2) | |
% First Name (H3) | |
% Last Name (H4) | |
% Phone (H5) | |
% Email (H6) | |
% Type (H7) | |
% Calendar (H8) | |
% Duke Unique ID (H9) | |
% Text Message? (H10) | |
% Phone Carrier (H11) | |
% Then read the data from the rest of the file | |
C = textscan(fid, '%s %s %s %s %s %s %s %s %s %s %s %s %s', 'delimiter', ','); | |
% StartDate {C1} | |
% StartTime (C2) | |
% EndDate (C3) | |
% EndTime (C4) | |
% First Name (C5) | |
% Last Name (C6) | |
% Phone (C7) | |
% Email (C8) | |
% Appointment Type (C9) | |
% Clinician (C10) | |
% Unique ID (C11) | |
% Text Message? (C12) | |
% Phone Carrier (C13) | |
% Now we convert a cell array into an array of strings so we can read each | |
% one, only for the fields that we are interested in. | |
FirstNames = C{5}; | |
LastNames = C{6}; | |
Phones = C{7}; | |
Emails = C{8}; | |
Txt = C{12}; | |
Carriers = C{13}; | |
fclose(fid); | |
clear C H fid; | |
%-------------------------------------------------------------------------- | |
% Download latest appointments from calendar to file | |
%-------------------------------------------------------------------------- | |
% FOR CALENDAR IN calendars (NEED TO ADD THIS LOOP HERE) | |
% CD to directory for saving current appointment files | |
cd('Y:/Scripts/Appointments/'); | |
% Download and save the calendar data | |
if strcmp(cal,'Imaging') | |
calie = urlwrite(schmoogie,'imaging.txt','get',{}); | |
meetingloc = 'Soc-Psych 07'; | |
elseif strcmp(cal,'Computer') | |
meetingloc = 'LSRC B Lobby'; | |
calie = urlwrite(yebya,'computer.txt','get',{}); | |
else | |
error('Incorrect specification of calendar: only accepts "Computer" and "Imaging"'); | |
end | |
%-------------------------------------------------------------------------- | |
% Read appointments from the file and save to variable | |
%-------------------------------------------------------------------------- | |
% Open the subject appointment file, which was an .ical file that we open as | |
% a text file | |
fln = fopen(calie); | |
% Create a subject count variable | |
appt_count=0; | |
% Set the current appointment date to today, so we can stop reading the | |
% file when the appointments go into the past. | |
Appointment=date; | |
% Set today's date in a number format for easy comparison | |
today = datenum(date); | |
while ~feof(fln) | |
% We need to make sure that we only read in appointments for today and | |
% in the future, so we do a comparison between the current appointment | |
% that is being read. We use a do-->while loop so that the comparison | |
% until after a subject has been | |
% Read in line | |
currentline = fgetl(fln); | |
% Look to see if we have a date line, which starts with 'DSTART' | |
if regexp(currentline, 'DTSTART', 'once'); | |
%if yes, pull the date and time from this line, and format | |
year = currentline(9:12); | |
month = currentline(13:14); | |
day = currentline(15:16); | |
appointment = datestr([ year ' ' month ' ' day ]); | |
time = currentline(18:21); | |
time = str2double(time); | |
% The time is 4 hours in the future, so we subtract 4: | |
time = time - 400; | |
% Convert military time to standard time | |
if (time > 1259) | |
time = time-1200; | |
period = 'pm'; | |
else | |
if (time >= 1200) && (time <= 1259) | |
period = 'pm'; | |
else | |
period = 'am'; | |
end | |
end | |
% Format time with a ":" by separating the last two characters | |
% from the first, and sticking them together with a ":" | |
time = num2str(time); | |
time_end = time(length(time)-1:length(time)); | |
time_beg = regexprep(time, time_end, '','once'); | |
% Put it all together into a user friendly format for printing | |
time = [ time_beg ':' time_end ' ' period ]; | |
% If the appointment is from before today, we don't want to do | |
% anything. | |
if(today > datenum(appointment)) | |
else | |
%Add another subject to the array if they aren't from the past | |
appt_count = appt_count +1; | |
APPTS(appt_count)= struct('First','','Last','','Email', '','Phone','','Appointment', appointment, 'Time', time,'Text','','Carrier',''); | |
end | |
end | |
% Look to see if we have a participant info line: | |
if regexp(currentline, 'DESCRIPTION', 'once'); | |
% Only read the line if there is data there, meaning the length | |
% is greater than 12 (the length of DESCRIPTION:) | |
if length(currentline) > 12 | |
% If the appointment is from the past, skip it, as we did | |
% above | |
if (today > datenum(appointment)) | |
else | |
%if yes, first get rid of the 'DESCRIPTION:Name: ' section | |
currentline = regexprep(currentline, currentline(1:18), '','once'); | |
% Put the first name into a variable by finding the end of it, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
name = currentline(1:marker-1); | |
currentline = regexprep(currentline, currentline(1:marker), '','once'); | |
% Put the last name into a variable by finding the end, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
lastname = currentline(1:marker-1); | |
% Add name to the data structure | |
APPTS(appt_count).First = deblank(name); | |
APPTS(appt_count).Last = deblank(lastname); | |
end | |
end | |
end | |
% Take in the name from the summary field, in case we need it | |
if regexp(currentline, 'SUMMARY', 'once'); | |
currentline = regexprep(currentline, currentline(1:8), '','once'); | |
% Put the first name into a variable by finding the end of it, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
name = currentline(1:marker-1); | |
currentline = regexprep(currentline, currentline(1:marker), '','once'); | |
% Put the last name into a variable by finding the end, | |
% marked by a space | |
marker = regexp(currentline, ' ', 'once'); | |
if isempty(marker) | |
lastname = currentline; | |
else | |
lastname = currentline(1:marker-1); | |
end | |
% In the case that the name was not present in the | |
% DESCRIPTION, we can get it from the Summary! | |
if isempty(APPTS(appt_count).First) | |
APPTS(appt_count).First = deblank(name); | |
end | |
if isempty(APPTS(appt_count).Last) | |
APPTS(appt_count).Last = deblank(lastname); | |
end | |
end | |
end | |
%-------------------------------------------------------------------------- | |
% Find rest of subject info by reading from Appointment file | |
%-------------------------------------------------------------------------- | |
% Need to find a way to decrease search through appointment file! Right now | |
% we look at everyone and compare First and Last Name. Since the | |
% information on the calendar is equivalent to the online system, | |
% these fields should match for each subject. If we have duplicates, then | |
% Vanessa can add phone number matching to the script. We place the | |
% current first and last name in a deblanked variable instead of | |
% referencing them from the array each time so we can easily calculate the | |
% length without blank spaces. | |
for i=1:length(FirstNames) | |
for k=1:length(APPTS) | |
currentfirst = deblank(FirstNames{i}); | |
currentlast = deblank(LastNames{i}); | |
if length(APPTS(k).First) >= length(currentfirst) | |
if strcmp(currentfirst,deblank(APPTS(k).First(1:length(currentfirst)))) | |
if length(APPTS(k).Last) >= length(currentlast) | |
if strcmp(currentlast,deblank(APPTS(k).Last(1:length(currentlast)))) | |
APPTS(k).Phone = deblank(Phones{i}); | |
APPTS(k).Text = Txt{i}; | |
APPTS(k).Carrier = Carriers{i}; | |
APPTS(k).Email = deblank(Emails{i}); | |
end | |
end | |
end | |
end | |
end | |
end | |
clear currentfirst currentlast i Phones Txt Carriers Emails FirstNames LastNames | |
%-------------------------------------------------------------------------- | |
% Send reminder emails | |
%-------------------------------------------------------------------------- | |
% Cycle through the participants in the array, and if the appointment is | |
% within the user specified number of days, send a reminder email with | |
% directions attached. | |
% Create date (x days away from today) to compare to. If the participant | |
% has an appointment on this day, he/she should receive a reminder about it | |
% today! | |
comparedate = today + days; | |
for i=1:size(APPTS,2) | |
if (datenum(APPTS(i).Appointment) == comparedate) | |
% ------------------------------------------------------------- | |
% FIRST SEND EMAIL | |
%-------------------------------------------------------------- | |
if strcmp(sendemail,'yes') | |
% we look at the email field to make sure that it isn't | |
% blank. If it is, this means that there was no match for | |
% the subject found in the database | |
if isempty(APPTS(i).Email)==0 | |
sendmail(APPTS(i).Email,[ 'Laboratory of Neurogenetics - ' cal ' Appointment Reminder' ],[ APPTS(i).First ', this is a reminder about your ' cal ' session appointment on ' datestr(APPTS(i).Appointment,'mmm dd, yyyy') ' at ' APPTS(i).Time '. Please come to ' meetingloc ' and see the attached reminder and directions sheet for location details about your appointment.' ],reminder_directions); | |
else | |
% We will want to know about this error, so we save the | |
% subject information to an array, to be emailed later. | |
APPT_ERRORS(email_count+1) = APPTS(i); | |
end | |
end | |
% ------------------------------------------------------------- | |
% SECOND SEND TEXT | |
%-------------------------------------------------------------- | |
if strcmp(sendtxt,'yes') | |
if strcmp(APPTS(i).Text,'yes') | |
send_text_message(APPTS(i).Phone,APPTS(i).Carrier, [ cal 'Appointment Reminder' ],[ cal ' appointment reminder: ' datestr(APPTS(i).Appointment,'mmm dd, yyyy') ' at ' APPTS(i).Time ' at ' meetingloc ]); | |
end | |
end | |
end | |
end | |
%-------------------------------------------------------------------------- | |
% Update sending log | |
%-------------------------------------------------------------------------- | |
% Initialize and print to file | |
lid = fopen('LOG.txt', 'a'); | |
% List the headings if the file is just being created | |
if exist('LOG.txt','file')==0 | |
fprintf(lid, 'Date,Calendar,Appt_Days_Away,First,Last,Email,Phone,Appointment,Time,Text,Carrier,'); | |
end | |
for i=1:numel(APPTS) | |
fprintf(lid,'\n%s', [ date ',' ]'); | |
fprintf(lid,'%s', [ cal ',' ]'); | |
fprintf(lid,'%s', [ days ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).First ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Last ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Email ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Phone ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Appointment ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Time ',' ]'); | |
fprintf(lid,'%s', [ APPTS(i).Text ',' ]'); | |
fprintf(lid,'%s', APPTS(i).Carrier); | |
end | |
fclose(lid); | |
%-------------------------------------------------------------------------- | |
% Email to send if there are errors in reading the calendar or sending | |
% brains | |
%-------------------------------------------------------------------------- | |
if exist('APPT_ERRORS','var') | |
save('APPT_ERRORS','APPTS.mat'); | |
if exist('contactemail','var') | |
sendmail(contactemail,'Message from Rem_Email.m',[ 'The script had subjects with missing emails on ' date ' while sending out ' days ' day reminders for the ' calendar ' calendar. The attached mat file contains these subjects!'],'APPTS.mat'); | |
end | |
end | |
% Exit from matlab to run the next script | |
exit | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function send_brains() | |
% SEND BRAIN IMAGES (send_brains.m) | |
% Vanessa Sochat | |
% | |
% This script takes in a list of subjects processed in SPM, creates a brain | |
% images zip with two .JPG images to send to the subject, and sends it. | |
%__________________________________________________________________________ | |
% | |
% DEPENDENCIES: You need to have the crop.m script in the same folder for | |
% this to work: http://vsoch.com/LONG/Vanessa/MATLAB/Send%20Brains/crop.m | |
% | |
% SUBJECT ID: This script is set up to work with DNS data - it is expecting | |
% IDs to have the format (DATE)_(SUBJECT ID). As the subject output images | |
% are named with the five numbers after the "_" (representing the subject | |
% ID) - this is the format that the script is expecting. If your subject | |
% IDs do not fit this format, you can nix the section that goes through the | |
% processed subject names and creates a string of modified IDs and just use | |
% the processed subject list raw without any changes to compare the files | |
% variable list to. | |
% | |
%__________________________________________________________________________ | |
% | |
% USAGE: send_brains() | |
% no input variables are required as the program takes them into a GUI. | |
%__________________________________________________________________________ | |
% | |
% ORGANIZATION: You should maintain the following file structure: | |
% Output images under DNS.01\Graphics\Brain Images | |
% Input Data: We will be using the processed highres under "anat" | |
% sdns01-005-00001-000001-01.img, to create the image from. | |
%__________________________________________________________________________ | |
% | |
% This script works by.... | |
% 1. Creating the list of potential sendees - whoever has been newly | |
% processed that week and does not have a brain image created yet. | |
% 2. The script then presents this list to the user, and asks if he/she | |
% would like to delete any participants. This is important because we | |
% could have a test folder under Processed, or potentially a participant | |
% that we don't want to send to. To delete a participant, the user simply | |
% enters the ID into the GUI, and then the script presents the user with | |
% the new list. There is no negative consequence of making a typo and | |
% entering an incorrect ID - the script will not find the ID in the list, | |
% and will present the identical list to the user, and he/she can enter | |
% the ID again. | |
% 3. Next, the script looks for the processed anatomical in the subject's | |
% anat directory under Processed. This image will normally always have | |
% the same name - however in rare cases when the name is different, | |
% for whatever reason, the script will not find the highres, and will | |
% present the user with a GUI to select the image that he/she would like | |
% to use for that participant. It then prepares two slice views of the | |
% highres, crops them, puts them together as a zip, moves the zip to the | |
% Graphics/Brain Images folder, and cleans up the old files. | |
% 4. Once all brain image zips have been created, the script prompts the | |
% user if he/she wants to send a brain image for each subject, and asks | |
% the user to enter the email. This process is fairly rapid and easy. | |
% In the case that the user mistypes an email, the easiest thing to do | |
% is delete the output image, and quickly run the script again. | |
% 5. As each address in entered, the script sends the email directly from | |
% MATLAB. | |
%__________________________________________________________________________ | |
%__________________________________________________________________________ | |
%-Global Variables | |
%----------------------------------------------------------------------- | |
fprintf('SEND_BRAIN.M Alpha\n Vanessa Sochat\n August, 2010\n'); | |
% Here the user specifies the experiment directory | |
homedir = spm_select(1,'dir','Select top of experiment directory','','N:'); | |
% Here the user specifies the output directory | |
output = spm_select(1,'dir','Select output directory','',[ homedir 'Graphics\' ] ); | |
% Here we set the Processed directory | |
processed_dir = horzcat(homedir,'Analysis\SPM\Processed\'); | |
% Add the path to the crop script | |
addpath(genpath('N:\DNS.01\Scripts\MATLAB\Vanessa\Send Brains')); | |
%-Identify subject list to make brain images for | |
%----------------------------------------------------------------------- | |
% Here the script compares the subjects in the "Processed" folder (meaning | |
% they have been processed and we can send a brain image) to the brain | |
% images in the output folder. The subject IDs that appear in the Processed | |
% folder but not the output folder are saved into a variable as they need | |
% to have brain images sent. Then, the user is allowed to delete subjects | |
% or text from the string, as it could be likely that there is a TEST | |
% folder or file in the processed directory that isn't a subject to send | |
% brain images to. | |
% First get the processed subjects | |
cd(processed_dir) | |
processed = [ ls ]; | |
% And then we grab the subject IDs who have had brain images. | |
cd(output); | |
files = [ ls ]; | |
% Initialize brain_list variables | |
brain_list = ''; | |
% We start at the third element because the first two are "." and ".." | |
for c = 3:size(processed,1) | |
% The subject ID always starts at the 10th spot, and ends at te 15th, so we | |
% use those coordinates to pull the subject IDs fromn the processed variable. | |
% You will need to change this if you have a different format, or you could | |
% just get rid of it completely and use the entire subject ID for the image names. | |
current_processed = processed(c,:); | |
% By default, add_var starts out as 'yes' and only gets changed to | |
% no if we find a matched subject ID. | |
add_var = 'yes'; | |
% VANESSA - MIGHT WANT TO ADD SOME SORT OF BREAK IF A MATCH IS | |
% FOUND, SO DON'T KEEP SEARCHING ONCE IS FOUND! | |
for i = 1:size(files,1) | |
% We take the first 5 characters of the file name, which is the | |
% subject's ID | |
subject = files(i,1:5); | |
if strcmp(current_processed(10:14),subject) | |
% If the processed subject can be found under the output files | |
% list, then the brain image has already been processed and we | |
% exit the loop without adding anything | |
add_var = 'no'; | |
end | |
end | |
% After cycling through the list of brain images already made, we only | |
% flag the subject as needing an image if the add_var is set to "yes" - | |
% meaning that no match was ever found. | |
if strcmp(add_var,'yes') | |
brain_list = [ brain_list;current_processed ]; | |
end | |
% and now we move on to the next processed subject at the start of the | |
% loop | |
end | |
% Clean up | |
clear current_processed subject | |
fprintf('%s\n','The list of subjects that need brain images is...'); | |
selections = listdlg('PromptString','Select Subjects to send to:','SelectionMode','multiple','ListString',brain_list); | |
% Pull the user selections from the brain list, and put them in the | |
% temp_list | |
add_count = 0; | |
for j = 1:size(selections,2) | |
add_count = add_count +1; | |
temp_list{add_count} = deblank(brain_list(selections(j),:)); | |
end | |
clear selections | |
%-Create brain images | |
%----------------------------------------------------------------------- | |
% This part of the script goes to the subject's anatomical directory, | |
% creates the brain image, and saves it to the output directory. | |
% Initialize graphic viewer | |
spm_figure('GetWin','Graphics'); | |
clear global st | |
% Read in logo and prepare file array (to make zip) just once! | |
I = imread('http://www.haririlab.com/img/logo_small.jpg'); | |
I = imresize(I, 2); | |
imagefiles{1}='slices.JPG'; | |
imagefiles{2}='sagittal.JPG'; | |
for i=1:size(temp_list,2) | |
subject = temp_list{i}; | |
% CD to subject's anatomical folder | |
if exist(horzcat(processed_dir,subject,'/anat/'),'dir') | |
cd(horzcat(processed_dir,subject,'/anat/')); | |
% If the default anatomical/highres exists, we use that | |
if exist(horzcat(processed_dir,subject,'/anat/sdns01-0005-00001-000001-01.img'),'file'); | |
anat = horzcat(processed_dir,subject,'/anat/sdns01-0005-00001-000001-01.img'); | |
% Create slices view and save... | |
SO=slover(); | |
SO.img(1).vol=spm_vol(anat); | |
SO.slices = [-36:2:70]; | |
SO=paint(SO); | |
% Add logo to slices image and save | |
image(I) | |
axis off | |
print -dtiff -noui slices.JPG | |
crop('slices.JPG'); | |
% Print sagittal view | |
SO=slover(); | |
SO.img(1).vol=spm_vol(anat); | |
SO.slices = [-2:10:52]; | |
SO.transform = 'sagittal'; | |
SO=paint(SO); | |
axis off | |
print -dtiff -noui sagittal.JPG | |
crop('sagittal.JPG'); | |
% Prepare zip of two files | |
zip('brain',imagefiles) | |
% Save final image to output directory | |
copyfile('brain.ZIP',[ output,subject(10:14),'.ZIP' ]); | |
delete brain.ZIP | |
delete slices.JPG | |
delete sagittal.JPG | |
clear SO | |
else | |
% If not, we give the user the option to select the file | |
h = msgbox([ 'Default highres does not exist for ' subject '!' ],'File Not Found','warn'); | |
uiwait(h); | |
files = [ ls ]; | |
[ selection use_anat ] = listdlg('PromptString','Select file, or CANCEL to skip','SelectionMode','single','ListString',files); | |
if use_anat == 1 | |
anat = files(selection,:); | |
% Create slices view and save... | |
SO=slover(); | |
SO.img(1).vol=spm_vol(anat); | |
SO.slices = [-36:2:70]; | |
SO=paint(SO); | |
% Add logo to slices image and save | |
image(I) | |
axis off | |
print -dtiff -noui slices.JPG | |
crop('slices.JPG'); | |
% Print sagittal view | |
SO=slover(); | |
SO.img(1).vol=spm_vol(anat); | |
SO.slices = [-2:10:52]; | |
SO.transform = 'sagittal'; | |
SO=paint(SO); | |
axis off | |
print -dtiff -noui sagittal.JPG | |
crop('sagittal.JPG'); | |
% Prepare zip of two files | |
zip('brain',imagefiles) | |
% Save final image to output directory | |
copyfile('brain.ZIP',[ output,subject(10:14),'.ZIP' ]); | |
delete brain.ZIP | |
delete slices.JPG | |
delete sagittal.JPG | |
clear SO | |
else | |
fprintf('%s%s%s\n','Please take not that subject ',subject,' has been skipped!'); | |
end | |
end | |
else | |
fprintf('%s%s%s\n','Subject ',subject,' does not have an anat folder under Processed!') | |
end | |
end | |
%-Send Brain Images | |
%----------------------------------------------------------------------- | |
% This part of the script goes to the output directory and sends an email | |
% for each subject | |
cd(output); | |
% Must be in the same folder as the script | |
load poozie.mat | |
% Then this code will set up the preferences properly: | |
setpref('Internet','E_mail',poozie); | |
setpref('Internet','SMTP_Server','smtp.gmail.com'); | |
setpref('Internet','SMTP_Username',poozie); | |
setpref('Internet','SMTP_Password',pooziepa); | |
props = java.lang.System.getProperties; | |
props.setProperty('mail.smtp.auth','true'); | |
props.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory'); | |
props.setProperty('mail.smtp.socketFactory.port','465'); | |
for i=1:size(temp_list,2) | |
subject = temp_list{i}; | |
send_var=spm_input([ 'Send image to:',subject(10:14),'?' ],1,'Yes|No'); | |
if strcmp(send_var,'Yes') | |
email = spm_input([ subject(10:14),' email address:' ],2,'s','',1); | |
% Check to see if the brain image exists, just in case! | |
if exist([ subject(10:14),'.ZIP' ],'file') | |
brain_image=[ subject(10:14),'.ZIP' ]; | |
% Send the email. Note that the first input is the address! | |
sendmail(email,'Laboratory of Neurogenetics - Brain Image','Attached, please find an image of your brain. This image is intended for personal use only. The image is NOT intended as and should NOT be used as a substitute for medical evaluation.',brain_image); | |
else | |
fprintf('%s%s/n',subject(10:14),'.ZIP cannot be found! Brain image not sent!'); | |
end | |
end | |
end | |
fprintf('%s\n','Done sending brain images!'); | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment