Report who the site managers are for the BCC
[htsworkflow.git] / htsworkflow / frontend / experiments / experiments.py
1 # some core functions of the exp tracker module
2 from datetime import datetime, timedelta
3 import os
4 import re
5
6 from django.http import HttpResponse
7 from htsworkflow.frontend import settings
8 from htsworkflow.frontend.experiments.models import FlowCell, DataRun
9 from htsworkflow.frontend.samples.models import Library
10 from django.core.exceptions import ObjectDoesNotExist
11 from django.core.mail import send_mail, mail_admins
12
13 def updStatus(request):
14     output=''
15     user = 'none'
16     pswd = ''
17     UpdatedStatus = 'unknown'
18     fcid = 'none'
19     runfolder = 'unknown'
20     ClIP = request.META['REMOTE_ADDR']
21
22     if hasattr(request, 'user'):
23       user = request.user
24
25     #Check access permission
26     if not (user.is_superuser and settings.ALLOWED_IPS.has_key(ClIP)): 
27         return HttpResponse("%s access denied from %s." % (user, ClIP))
28
29     # ~~~~~~Parameters for the job ~~~~
30     if request.REQUEST.has_key('fcid'):
31       fcid = request.REQUEST['fcid']
32     else:
33       return HttpResponse('missing fcid')
34     
35     if request.REQUEST.has_key('runf'):
36       runfolder = request.REQUEST['runf']
37     else:
38       return HttpResponse('missing runf')
39
40     
41     if request.REQUEST.has_key('updst'):
42       UpdatedStatus = request.REQUEST['updst']
43     else:
44       return HttpResponse('missing status')
45     
46     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
47
48     # Update Data Run status in DB
49     # Try get rec. If not found return 'entry not found + <fcid><runfolder>', if found try update and return updated 
50     try:
51       rec = DataRun.objects.get(run_folder=runfolder)
52       rec.run_status = UpdatedStatus
53
54       #if there's a message update that too
55       mytimestamp = datetime.now().__str__()
56       mytimestamp = re.sub(pattern=":[^:]*$",repl="",string=mytimestamp)
57       if request.REQUEST.has_key('msg'):
58         rec.run_note += ", "+request.REQUEST['msg']+" ("+mytimestamp+")"
59       else :
60         if UpdatedStatus == '1':
61           rec.run_note = "Started ("+mytimestamp+")"
62
63       rec.save()
64       output = "Hello "+settings.ALLOWED_IPS[ClIP]+". Updated to:'"+DataRun.RUN_STATUS_CHOICES[int(UpdatedStatus)][1].__str__()+"'"
65     except ObjectDoesNotExist:
66       output = "entry not found: "+fcid+", "+runfolder
67
68
69     #Notify researcher by email
70     # Doesn't work
71     #send_mail('Exp Tracker', 'Data Run Status '+output, 'rrauch@stanford.edu', ['rrrami@gmail.com'], fail_silently=False)
72     #mail_admins("test subject", "testing , testing", fail_silently=False)
73     # gives error: (49, "Can't assign requested address")
74     return HttpResponse(output)
75
76 def generateConfile(request,fcid):
77     #granted = False
78     #ClIP = request.META['REMOTE_ADDR']
79     #if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
80
81     #if not granted: return HttpResponse("access denied.")
82
83     config = ['READ_LENGTH 25']
84     config += ['ANALYSIS eland']
85     config += ['GENOME_FILE all_chr.fa']
86     config += ['ELAND_MULTIPLE_INSTANCES 8']
87     genome_dir = 'GENOME_DIR /Volumes/Genomes/'
88     eland_genome = 'ELAND_GENOME /Volumes/Genomes/'
89     
90     try:                                                                                                                                              
91       fc = FlowCell.objects.get(flowcell_id=fcid)
92       for lane in fc.lane_set.all():
93           print dir(lane.library.library_species)
94           config += [ str(lane.lane_number) +":" + \
95                       genome_dir + lane.library.library_species.scientific_name ]
96           config += [ str(lane.lane_number) +":" + \
97                       eland_genome + lane.library.library_species.scientific_name ]
98       
99     except ObjectDoesNotExist:
100       config = 'Entry not found for fcid  = '+fcid
101
102     return os.linesep.join(config)
103
104 def getConfile(req):
105     granted = False
106     ClIP = req.META['REMOTE_ADDR']
107     if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
108
109     if not granted: return HttpResponse("access denied. IP: "+ClIP)
110
111     fcid = 'none'
112     cnfgfile = 'Nothing found'
113     runfolder = 'unknown'
114     request = req.REQUEST
115     print request, dir(request)
116     print request['fcid'], request.has_key('fcid')
117     print request['runf']
118     if request.has_key('fcid'):
119       fcid = request['fcid']
120       if request.has_key('runf'):
121         runfolder = request['runf']
122         try:
123           rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
124           cnfgfile = rec.config_params
125           #match_str = re.compile(r"READ_LENGTH.+$")
126           match_str = re.compile('^READ_LENGTH.+')
127           if not match_str.search(cnfgfile):
128             cnfgfile = generateConfile(request,fcid)
129             if match_str.search(cnfgfile):
130               rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
131               rec.config_params = cnfgfile
132               rec.save()
133             else:
134               cnfgfile = 'Failed generating config params for RunFolder = '+runfolder +', Flowcell id = '+ fcid+ ' Config Text:\n'+cnfgfile  
135             
136         except ObjectDoesNotExist:
137           cnfgfile = 'Entry not found for RunFolder = '+runfolder
138
139     return HttpResponse(cnfgfile, mimetype='text/plain')
140
141 def getLaneLibs(req):
142     granted = False
143     ClIP = req.META['REMOTE_ADDR']
144     if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
145
146     if not granted: return HttpResponse("access denied.")
147
148     request = req.REQUEST
149     fcid = 'none'
150     outputfile = ''
151     if request.has_key('fcid'):
152       fcid = request['fcid']
153       try:                                
154         rec = FlowCell.objects.get(flowcell_id=fcid)
155         #Ex: 071211
156         year = datetime.today().year.__str__()
157         year = replace(year,'20','')
158         month = datetime.today().month
159         if month < 10: month = "0"+month.__str__()
160         else: month = month.__str__() 
161         day = datetime.today().day
162         if day < 10: day = "0"+day.__str__()
163         else: day = day.__str__()
164         mydate = year+month+day
165         outputfile = '<?xml version="1.0" ?>'
166         outputfile += '\n<SolexaResult Date="'+mydate+'" Flowcell="'+fcid+'" Client="'+settings.ALLOWED_IPS[ClIP]+'">'
167         outputfile += '\n<Lane Index="1" Name="'+rec.lane_1_library.library_name+'" Library="'+rec.lane_1_library.library_id+'" Genome="'+rec.lane_1_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
168         outputfile += '\n<Lane Index="2" Name="'+rec.lane_2_library.library_name+'" Library="'+rec.lane_2_library.library_id+'" Genome="'+rec.lane_2_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
169         outputfile += '\n<Lane Index="3" Name="'+rec.lane_3_library.library_name+'" Library="'+rec.lane_3_library.library_id+'" Genome="'+rec.lane_3_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
170         outputfile += '\n<Lane Index="4" Name="'+rec.lane_4_library.library_name+'" Library="'+rec.lane_4_library.library_id+'" Genome="'+rec.lane_4_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
171         outputfile += '\n<Lane Index="5" Name="'+rec.lane_5_library.library_name+'" Library="'+rec.lane_5_library.library_id+'" Genome="'+rec.lane_5_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
172         outputfile += '\n<Lane Index="6" Name="'+rec.lane_6_library.library_name+'" Library="'+rec.lane_6_library.library_id+'" Genome="'+rec.lane_6_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
173         outputfile += '\n<Lane Index="7" Name="'+rec.lane_7_library.library_name+'" Library="'+rec.lane_7_library.library_id+'" Genome="'+rec.lane_7_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
174         outputfile += '\n<Lane Index="8" Name="'+rec.lane_8_library.library_name+'" Library="'+rec.lane_8_library.library_id+'" Genome="'+rec.lane_8_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
175         outputfile += '\n</SolexaResult>'
176       except ObjectDoesNotExist:
177         outputfile = 'Flowcell entry not found for: '+fcid
178     else: outputfile = 'Missing input: flowcell id'
179
180     return HttpResponse(outputfile, mimetype='text/plain')
181
182 def estimateFlowcellDuration(flowcell):
183     """
184     Attempt to estimate how long it will take to run a flowcell
185
186     """
187     # (3600 seconds * 1.5 hours per cycle )
188     sequencing_seconds_per_cycle= 3600 * 1.5
189     # 800 is a rough guess
190     pipeline_seconds_per_cycle = 800
191     
192     cycles = flowcell.read_length
193     if flowcell.paired_end:
194         cycles *= 2
195     sequencing_time = timedelta(0, cycles * sequencing_seconds_per_cycle)
196     analysis_time = timedelta(0, cycles * pipeline_seconds_per_cycle)
197     estimate_mid = sequencing_time + analysis_time
198     # floor estimate_mid
199     estimate_low = timedelta(estimate_mid.days, 0)
200     # floor estimate_mid and add a day
201     estimate_high = timedelta(estimate_mid.days+1, 0)
202     
203     return (estimate_low, estimate_high)
204     
205
206 def makeUserLaneMap(flowcell):
207     """
208     Given a flowcell return a mapping of users interested in
209     the libraries on those lanes.
210     """
211     users = {}
212
213     for lane in flowcell.lane_set.all():
214         for affiliation in lane.library.affiliations.all():
215             for user in affiliation.users.all():
216                 users.setdefault(user,[]).append(lane)
217
218     return users
219
220 def getUsersForFlowcell(flowcell):
221     users = set()
222     
223     for lane in flowcell.lane_set.all():
224         for affiliation in lane.library.affiliations.all():
225             for user in affiliation.users.all():
226                 users.add(user)
227                 
228     return users
229     
230 def makeUserLibraryMap(libraries):
231     """
232     Given an interable set of libraries return a mapping or
233     users interested in those libraries.
234     """
235     users = {}
236     
237     for library in libraries:
238         for affiliation in library.affiliations.all():
239             for user in affiliation.users.all():
240                 users.setdefault(user,[]).append(library)
241                 
242     return users
243
244 def makeAffiliationLaneMap(flowcell):
245     affs = {}
246
247     for lane in flowcell.lane_set.all():
248         for affiliation in lane.library.affiliations.all():
249             affs.setdefault(affiliation,[]).append(lane)
250
251     return affs
252
253 def makeEmailLaneMap(flowcell):
254     """
255     Create a list of email addresses and the lanes associated with those users.
256
257     The email addresses can come from both the "users" table and the "affiliations" table.
258     """
259     emails = {}
260     for lane in flowcell.lane_set.all():
261         for affiliation in lane.library.affiliations.all():
262             if affiliation.email is not None and len(affiliation.email) > 0:
263                 emails.setdefault(affiliation.email,set()).add(lane)
264             for user in affiliation.users.all():
265                 if user.email is not None and len(user.email) > 0:
266                     emails.setdefault(user.email,set()).add(lane)
267
268     return emails