| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | ## |
|---|
| 3 | ## |
|---|
| 4 | ## This file is part of CDS Indico. |
|---|
| 5 | ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN. |
|---|
| 6 | ## |
|---|
| 7 | ## CDS Indico is free software; you can redistribute it and/or |
|---|
| 8 | ## modify it under the terms of the GNU General Public License as |
|---|
| 9 | ## published by the Free Software Foundation; either version 2 of the |
|---|
| 10 | ## License, or (at your option) any later version. |
|---|
| 11 | ## |
|---|
| 12 | ## CDS Indico is distributed in the hope that it will be useful, but |
|---|
| 13 | ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 15 | ## General Public License for more details. |
|---|
| 16 | ## |
|---|
| 17 | ## You should have received a copy of the GNU General Public License |
|---|
| 18 | ## along with CDS Indico; if not, write to the Free Software Foundation, Inc., |
|---|
| 19 | ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 20 | |
|---|
| 21 | import tempfile, os, getopt, sys, base64, socket |
|---|
| 22 | import httplib, mimetypes, urlparse, simplejson |
|---|
| 23 | from MaKaC.common.Configuration import Config |
|---|
| 24 | from MaKaC import conference |
|---|
| 25 | |
|---|
| 26 | #URL_RESPONSE = "http://pcdh20.cern.ch/indico/getConvertedFile.py" |
|---|
| 27 | #SERVER = 'http://pcdh20.cern.ch/getSegFile.py'#'http://pcuds01.cern.ch/getSegFile.py' |
|---|
| 28 | |
|---|
| 29 | SEGMENT_SIZE = 500000 |
|---|
| 30 | DEFAUTL_ENCODING = "utf-8" |
|---|
| 31 | |
|---|
| 32 | def get_content_type(filename): |
|---|
| 33 | return mimetypes.guess_type(filename)[0] or 'application/octet-stream' |
|---|
| 34 | |
|---|
| 35 | def writeLog(m): |
|---|
| 36 | ERROR_LOG_FOLDER="c:/tmp" |
|---|
| 37 | if os.path.isdir(ERROR_LOG_FOLDER): |
|---|
| 38 | l=open(os.path.join(ERROR_LOG_FOLDER, "FILE-CONVERTER-ERROR.log"),"a") |
|---|
| 39 | l.write("%s\n"%m) |
|---|
| 40 | l.close() |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | class FileConverter: |
|---|
| 44 | |
|---|
| 45 | def convert(filepath, converter, uid): |
|---|
| 46 | pass |
|---|
| 47 | convert=staticmethod(convert) |
|---|
| 48 | |
|---|
| 49 | def storeConvertedFile(params): |
|---|
| 50 | pass |
|---|
| 51 | storeConvertedFile=staticmethod(storeConvertedFile) |
|---|
| 52 | |
|---|
| 53 | def hasAvailableConversionsFor(ext): |
|---|
| 54 | pass |
|---|
| 55 | hasAvailableConversionsFor=staticmethod(hasAvailableConversionsFor) |
|---|
| 56 | |
|---|
| 57 | class CDSConvFileConverter(FileConverter): |
|---|
| 58 | |
|---|
| 59 | _availableExt=[".ppt", ".doc", ".pptx", ".docx", ".odp", ".sxi" ] |
|---|
| 60 | |
|---|
| 61 | def convert(filepath, converter, material): |
|---|
| 62 | # Material UID |
|---|
| 63 | materialUID="%s"%material.getLocator() |
|---|
| 64 | # Getting variables |
|---|
| 65 | responseURL = Config.getInstance().getFileConverterResponseURL() |
|---|
| 66 | serverURL = Config.getInstance().getFileConverterServerURL() |
|---|
| 67 | up = urlparse.urlparse(serverURL) |
|---|
| 68 | if up[0] == "": |
|---|
| 69 | #writeLog("Wrong conversion server URL") |
|---|
| 70 | return |
|---|
| 71 | host = up[1] |
|---|
| 72 | selector = up[2] |
|---|
| 73 | # Checking the file |
|---|
| 74 | localFile = filepath.strip() |
|---|
| 75 | localFile = localFile.replace("\\", "/") |
|---|
| 76 | filename = localFile.split("/")[-1] |
|---|
| 77 | if not os.access(localFile, os.F_OK): |
|---|
| 78 | #writeLog("Local file to upload invalid") |
|---|
| 79 | return False |
|---|
| 80 | fic=open(localFile, "rb") |
|---|
| 81 | segnum=0 |
|---|
| 82 | segsize = SEGMENT_SIZE |
|---|
| 83 | filekey = 'segfile' |
|---|
| 84 | i = 0 |
|---|
| 85 | |
|---|
| 86 | try : |
|---|
| 87 | h = httplib.HTTP(host) |
|---|
| 88 | except Exception, e: |
|---|
| 89 | #writeLog("Error : Can't connect to host:%s"%host) |
|---|
| 90 | return False |
|---|
| 91 | |
|---|
| 92 | while 1: |
|---|
| 93 | |
|---|
| 94 | temp = fic.read(segsize) |
|---|
| 95 | |
|---|
| 96 | segnum = segnum + 1 |
|---|
| 97 | BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$' |
|---|
| 98 | CRLF = '\r\n' |
|---|
| 99 | L = [] |
|---|
| 100 | |
|---|
| 101 | if len(temp) < segsize: |
|---|
| 102 | lastseg = 1 |
|---|
| 103 | |
|---|
| 104 | L.append('--' + BOUNDARY) |
|---|
| 105 | L.append('Content-Disposition: form-data; name="dirresponse"') |
|---|
| 106 | L.append('') |
|---|
| 107 | L.append(materialUID) |
|---|
| 108 | |
|---|
| 109 | L.append('--' + BOUNDARY) |
|---|
| 110 | L.append('Content-Disposition: form-data; name="urlresponse"') |
|---|
| 111 | L.append('') |
|---|
| 112 | L.append(responseURL) |
|---|
| 113 | |
|---|
| 114 | L.append('--' + BOUNDARY) |
|---|
| 115 | L.append('Content-Disposition: form-data; name="converter"') |
|---|
| 116 | L.append('') |
|---|
| 117 | L.append(converter) |
|---|
| 118 | else: |
|---|
| 119 | lastseg = 0 |
|---|
| 120 | L.append('--' + BOUNDARY) |
|---|
| 121 | L.append('Content-Disposition: form-data; name="filename"') |
|---|
| 122 | L.append('') |
|---|
| 123 | L.append(filename) |
|---|
| 124 | |
|---|
| 125 | L.append('--' + BOUNDARY) |
|---|
| 126 | L.append('Content-Disposition: form-data; name="segnum"') |
|---|
| 127 | L.append('') |
|---|
| 128 | L.append('%i' % segnum) |
|---|
| 129 | |
|---|
| 130 | L.append('--' + BOUNDARY) |
|---|
| 131 | L.append('Content-Disposition: form-data; name="lastseg"') |
|---|
| 132 | L.append('') |
|---|
| 133 | L.append('%i' % lastseg) |
|---|
| 134 | |
|---|
| 135 | """ |
|---|
| 136 | add the segment |
|---|
| 137 | """ |
|---|
| 138 | |
|---|
| 139 | L.append('--' + BOUNDARY) |
|---|
| 140 | L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (filekey, filename)) |
|---|
| 141 | L.append('Content-Type: %s' % get_content_type(filename)) |
|---|
| 142 | L.append('') |
|---|
| 143 | L.append(temp) |
|---|
| 144 | |
|---|
| 145 | L.append('--' + BOUNDARY + '--') |
|---|
| 146 | L.append('') |
|---|
| 147 | body = CRLF.join(L) |
|---|
| 148 | content_type = 'multipart/form-data; boundary=%s' % BOUNDARY |
|---|
| 149 | |
|---|
| 150 | try: |
|---|
| 151 | h.putrequest('POST', selector) |
|---|
| 152 | h.putheader('content-type', content_type) |
|---|
| 153 | h.putheader('content-length', str(len(body))) |
|---|
| 154 | h.endheaders() |
|---|
| 155 | h.send(body) |
|---|
| 156 | except: |
|---|
| 157 | #writeLog("Exception while sending file to the CDSconv server") |
|---|
| 158 | pass |
|---|
| 159 | try: |
|---|
| 160 | errcode, errmsg, headers = h.getreply() |
|---|
| 161 | except Exception, e: |
|---|
| 162 | #writeLog(e) |
|---|
| 163 | pass |
|---|
| 164 | i = i + 1 |
|---|
| 165 | if lastseg == 1 : |
|---|
| 166 | #print "\n%s\n"%(h.getfile().read()) |
|---|
| 167 | break |
|---|
| 168 | fic.close() |
|---|
| 169 | #writeLog("File uploaded") |
|---|
| 170 | convert=staticmethod(convert) |
|---|
| 171 | |
|---|
| 172 | def _getMaterialObj(owner, id): |
|---|
| 173 | if id=="video": |
|---|
| 174 | return owner.getVideo() |
|---|
| 175 | elif id=="paper": |
|---|
| 176 | return owner.getPaper() |
|---|
| 177 | elif id=="slides": |
|---|
| 178 | return owner.getSlides() |
|---|
| 179 | elif id=="poster": |
|---|
| 180 | return owner.getPoster() |
|---|
| 181 | elif id=="minutes": |
|---|
| 182 | return owner.getMinutes() |
|---|
| 183 | else: |
|---|
| 184 | try: |
|---|
| 185 | return owner.getMaterialById(id) |
|---|
| 186 | except KeyError, e: |
|---|
| 187 | pass |
|---|
| 188 | return None |
|---|
| 189 | _getMaterialObj=staticmethod(_getMaterialObj) |
|---|
| 190 | |
|---|
| 191 | def _getMaterial(locator): |
|---|
| 192 | ch=conference.ConferenceHolder() |
|---|
| 193 | if locator.has_key("confId") and locator.has_key("materialId"): |
|---|
| 194 | c=ch.getById(locator["confId"]) |
|---|
| 195 | # ---------- Conference ---------- |
|---|
| 196 | if c is not None: |
|---|
| 197 | # ---------- Session ---------- |
|---|
| 198 | if locator.has_key("sessionId"): |
|---|
| 199 | s=c.getSessionById(locator["sessionId"]) |
|---|
| 200 | if s is not None: |
|---|
| 201 | # ---------- Contribution ---------- |
|---|
| 202 | if locator.has_key("contribId"): |
|---|
| 203 | contrib=c.getContributionById(locator["contribId"]) |
|---|
| 204 | if contrib is not None: |
|---|
| 205 | # ---------- Subcontribution ---------- |
|---|
| 206 | if locator.has_key("subContId"): |
|---|
| 207 | subContrib=contrib.getSubContributionById(locator["subContId"]) |
|---|
| 208 | if subContrib is not None: |
|---|
| 209 | return CDSConvFileConverter._getMaterialObj(subContrib, locator["materialId"]) |
|---|
| 210 | else: |
|---|
| 211 | return CDSConvFileConverter._getMaterialObj(contrib, locator["materialId"]) |
|---|
| 212 | else: |
|---|
| 213 | return CDSConvFileConverter._getMaterialObj(s, locator["materialId"]) |
|---|
| 214 | # ---------- Contribution ---------- |
|---|
| 215 | elif locator.has_key("contribId"): |
|---|
| 216 | contrib=c.getContributionById(locator["contribId"]) |
|---|
| 217 | if contrib is not None: |
|---|
| 218 | # ---------- Subcontribution ---------- |
|---|
| 219 | if locator.has_key("subContId"): |
|---|
| 220 | subContrib=contrib.getSubContributionById(locator["subContId"]) |
|---|
| 221 | if subContrib is not None: |
|---|
| 222 | return CDSConvFileConverter._getMaterialObj(subContrib, locator["materialId"]) |
|---|
| 223 | else: |
|---|
| 224 | return CDSConvFileConverter._getMaterialObj(contrib, locator["materialId"]) |
|---|
| 225 | else: |
|---|
| 226 | return CDSConvFileConverter._getMaterialObj(c, locator["materialId"]) |
|---|
| 227 | |
|---|
| 228 | return None |
|---|
| 229 | _getMaterial=staticmethod(_getMaterial) |
|---|
| 230 | |
|---|
| 231 | def _getNewTempFile(): |
|---|
| 232 | cfg = Config.getInstance() |
|---|
| 233 | tempPath = cfg.getUploadedFilesTempDir() |
|---|
| 234 | tempFileName = tempfile.mkstemp( suffix="Indico.tmp", dir = tempPath )[1] |
|---|
| 235 | return tempFileName |
|---|
| 236 | _getNewTempFile=staticmethod(_getNewTempFile) |
|---|
| 237 | |
|---|
| 238 | def _saveFileToTemp( params ): |
|---|
| 239 | fileName = CDSConvFileConverter._getNewTempFile() |
|---|
| 240 | f = open( fileName, "wb" ) |
|---|
| 241 | f.write( base64.decodestring(params["content"]) ) |
|---|
| 242 | f.close() |
|---|
| 243 | return fileName |
|---|
| 244 | _saveFileToTemp=staticmethod(_saveFileToTemp) |
|---|
| 245 | |
|---|
| 246 | def storeConvertedFile(requestIP, params): |
|---|
| 247 | |
|---|
| 248 | """ returns the path to the temp file used in the process |
|---|
| 249 | so that it can be deleted at a later stage """ |
|---|
| 250 | |
|---|
| 251 | # extract the server name from the url |
|---|
| 252 | serverURL = Config.getInstance().getFileConverterServerURL() |
|---|
| 253 | up = urlparse.urlparse(serverURL) |
|---|
| 254 | |
|---|
| 255 | # check that the request comes from the conversion server |
|---|
| 256 | if socket.gethostbyname(up[1]) != requestIP: |
|---|
| 257 | return |
|---|
| 258 | |
|---|
| 259 | if params["status"] == '1': |
|---|
| 260 | locator={} |
|---|
| 261 | # python dicts come with ' instead of " by default |
|---|
| 262 | # using a json encoder on the server side would help... |
|---|
| 263 | locator = simplejson.loads(params["directory"].replace('\'','"')) |
|---|
| 264 | |
|---|
| 265 | mat=CDSConvFileConverter._getMaterial(locator) |
|---|
| 266 | if mat is not None: |
|---|
| 267 | filePath = CDSConvFileConverter._saveFileToTemp( params ) |
|---|
| 268 | fileName = params["filename"] |
|---|
| 269 | if not mat.hasFile(fileName): |
|---|
| 270 | f = conference.LocalFile() |
|---|
| 271 | f.setName(fileName) |
|---|
| 272 | f.setFileName( fileName ) |
|---|
| 273 | f.setFilePath( filePath ) |
|---|
| 274 | mat.addResource( f ) |
|---|
| 275 | return filePath |
|---|
| 276 | else: |
|---|
| 277 | #writeLog("Locator does not exist for file \"%s\": \n-locator:%s\nmessage:%s"%(params["filename"], params["directory"], params["error_message"])) |
|---|
| 278 | pass |
|---|
| 279 | else: |
|---|
| 280 | #Here it should be processed the received error from the conversion server. |
|---|
| 281 | #writeLog("Error converting file \"%s\": \n-locator:%s\nmessage:%s"%(params["filename"], params["directory"], params["error_message"])) |
|---|
| 282 | pass |
|---|
| 283 | storeConvertedFile=staticmethod(storeConvertedFile) |
|---|
| 284 | |
|---|
| 285 | def hasAvailableConversionsFor(ext): |
|---|
| 286 | if ext in CDSConvFileConverter._availableExt: |
|---|
| 287 | return True |
|---|
| 288 | return False |
|---|
| 289 | hasAvailableConversionsFor=staticmethod(hasAvailableConversionsFor) |
|---|