SHARE
TWEET

AWS S3 Python Boto File Utils Example

ericsaupe Dec 3rd, 2013 181 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class FileUtils:
  2.         def __init__(self, companyID):
  3.                 self.companyID = companyID
  4.                 self.rootFolder = '%sClient Number/%s/' % (settings.FILE_ROOT, companyID)
  5.                 self.s3Connection = boto.connect_s3() #This opens the connection to our s3 instance
  6.                 self.s3Bucket = self.s3Connection.get_bucket(settings.S3_BUCKET) #This gets the s3 bucket
  7.  
  8.         def save_file(self, path=None, data=None):
  9.                 """
  10.                 This method saves a file to the given path.  If none is given for either the path or the data it will return false.
  11.                 Parameters:
  12.                         path - The path to save the file in
  13.                         data - The file to be saved
  14.  
  15.                 Returns:
  16.                         True if the file was saved successfully otherwise an error will be thrown.
  17.                 """
  18.                 if data is None or path is None:
  19.                         return False
  20.                 if not "Files/Client Number/" in path:
  21.                         path = "%s%s" % (self.rootFolder, path)
  22.                 k = self.s3Bucket.new_key(path)
  23.  
  24.                 if (path[path.rfind('.'):] == '.pdf'):
  25.                         k.set_contents_from_string(data, headers={'Content-Type': 'application/pdf'})
  26.                 else:
  27.                         k.set_contents_from_string(data)
  28.  
  29.                 return self.get_contents(None, path[:path.rfind('/') + 1])
  30.  
  31.         def create_folder(self, request, path=""):
  32.                 """
  33.                 This method creates a folder in the given path.  If one is not given it is created in the root.
  34.  
  35.                 Parameters:
  36.                         path - where the folder will be created.  Empty string will create the folder in root.
  37.  
  38.                 Returns:
  39.                         True if the folder was created succesfully.
  40.                 """
  41.                 if request.POST.get('name') is None:
  42.                         return False
  43.                 newFolderName = request.POST.get('name', '')
  44.                 if path == '':
  45.                         path = self.rootFolder
  46.                 newFolder = '%s%s/' % (path, newFolderName)
  47.                 try:
  48.                         k = self.s3Bucket.new_key(newFolder)
  49.                         k.set_contents_from_string("")
  50.                 except:
  51.                         return HttpResponse("Folder Name in Use", mimetype="text/plain")
  52.  
  53.                 return self.get_contents(None, path)
  54.  
  55.         def delete(self, request, path=None):
  56.                 """
  57.                 This method deletes the element given in path.
  58.  
  59.                 Parameters:
  60.                         path - path to the element to be deleted
  61.  
  62.                 Returns:
  63.                         Contents of the parent folder
  64.                 """
  65.                 if path is None:
  66.                         return False
  67.  
  68.                 #get current shares that are contained in this share and unshare them
  69.                 PendingFileSharesPermissions.objects.filter(path__path__contains=path).delete()
  70.                 PendingFileShares.objects.filter(path__contains=path).delete()
  71.                 #get current shares that are contained in this share and unshare them
  72.                 FileSharesPermissions.objects.filter(path__path__contains=path).delete()
  73.                 FileShares.objects.filter(path__contains=path).delete()
  74.  
  75.                 if FileUtils.is_file(path):
  76.                         parent = path[:path.rfind('/') + 1]
  77.                 elif FileUtils.is_folder(path):
  78.                         keyList = self.s3Bucket.list(prefix=path)
  79.                         for key in keyList:
  80.                                 self.s3Bucket.delete_key(key.name)
  81.                         parent = path[:path.rfind('/')]
  82.                         parent = parent[:parent.rfind('/') + 1]
  83.                 k = self.s3Bucket.get_key(path)
  84.                 if (k is not None):
  85.                         self.s3Bucket.delete_key(k)
  86.                 return self.get_contents(None, parent)
  87.  
  88.         def get_file(self, path=None, isFile=True):
  89.                 """
  90.                 This method fetches the file at path and returns it.
  91.  
  92.                 Parameters:
  93.                         path - The path of the requested file
  94.  
  95.                 Returns:
  96.                         The file at the requested path
  97.                 """
  98.                 if path is None:
  99.                         return None
  100.                 if isFile:
  101.                         allowedAccess = False
  102.                         if path[:self.rootFolder.__len__()] == self.rootFolder:
  103.                                 allowedAccess = True
  104.                         else:
  105.                                 shares = FileSharesPermissions.objects.filter(company=self.companyID)
  106.                                 for share in shares:
  107.                                         if share.path.path in path:
  108.                                                 allowedAccess = True
  109.                                                 break
  110.                         if not allowedAccess:
  111.                                 return False
  112.                 k = self.s3Bucket.get_key(path)
  113.                 url = ''
  114.                 if k:
  115.                         url = k.generate_url(120)
  116.                 return url
  117.  
  118.         def get_raw_file(self, path=None, isFile=True):
  119.                 """
  120.                 This method fetches the file at path and returns it.
  121.  
  122.                 Parameters:
  123.                         path - The path of the requested file
  124.  
  125.                 Returns:
  126.                         The file at the requested path
  127.                 """
  128.                 if path is None:
  129.                         return None
  130.                 if isFile:
  131.                         allowedAccess = False
  132.                         if path[:self.rootFolder.__len__()] == self.rootFolder:
  133.                                 allowedAccess = True
  134.                         else:
  135.                                 shares = FileSharesPermissions.objects.filter(company=self.companyID)
  136.                                 for share in shares:
  137.                                         if share.path.path in path:
  138.                                                 allowedAccess = True
  139.                                                 break
  140.                         if not allowedAccess:
  141.                                 return False
  142.                 k = self.s3Bucket.get_key(path)
  143.                 fileName = k.get_contents_as_string()
  144.                 return fileName
  145.  
  146.         def move(self, request, path=None):
  147.                 """
  148.                 This method renames the file by copying the key to a new key with the new name and deleting the old one.
  149.                 Functions like the Unix move command.
  150.  
  151.                 Parameters:
  152.                         request - contains POST data with the new name
  153.                         path - The relative path of the item to be moved
  154.  
  155.                 Returns:
  156.                         Contents of the parent folder to be used in refreshing the list
  157.                 """
  158.                 if path is None:
  159.                         return None
  160.                 #Get the path
  161.                 shared = True
  162.                 if path[:self.rootFolder.__len__()] == self.rootFolder:
  163.                         shared = False
  164.                 #Move the file or folder
  165.                 if FileUtils.is_file(path):
  166.                         #Move places the file into the new folder
  167.                         if request.POST.get('move') == 'true':
  168.                                 if request.POST.get('name') != "fileslist":
  169.                                         newFolder = "%s%s" % (self.rootFolder, request.POST.get('name'))
  170.                                 else:
  171.                                         newFolder = "%s" % (self.rootFolder)
  172.                                 if not self.s3Bucket.get_key(newFolder):
  173.                                         k = self.s3Bucket.new_key(newFolder)
  174.                                         k.set_contents_from_string("")
  175.                                 newName = "%s%s" % (newFolder, path[path.rfind('/')+1:])
  176.                         #Non-Move calls rename the file in its current folder
  177.                         else:
  178.                                 if not self.s3Bucket.get_key(path[:path.rfind('/')+1]):
  179.                                         k = self.s3Bucket.new_key(path[:path.rfind('/')+1])
  180.                                         k.set_contents_from_string("")
  181.                                 newName = "%s%s%s" % (path[:path.rfind('/')+1], request.POST.get('name'), path[path.rfind('.'):])
  182.                         self.s3Bucket.copy_key(newName, settings.S3_BUCKET, path)
  183.                         #If the file is not in a shared directory we can remove it and update file sharing if it exists
  184.                         if not shared:
  185.                                 shared = FileShares.objects.filter(path=path)
  186.                                 for share in shared:
  187.                                         share.path = newName
  188.                                         share.save()
  189.                                 self.s3Bucket.delete_key(path)
  190.                 #Folder names need to be pulled out of their current path
  191.                 elif FileUtils.is_folder(path):
  192.                         #Move holds the folder name the same but appends it to the desitination folder
  193.                         if request.POST.get('move') == 'true':
  194.                                 newName = path[:path.rfind('/')]
  195.                                 newName = newName[newName.rfind('/')+1:]
  196.                                 newName = "%s%s%s/" % (self.rootFolder, request.POST.get('name'), newName)
  197.                         #Rename changes the folder name
  198.                         else:
  199.                                 newName = path[:path.rfind('/')]
  200.                                 newName = newName[:newName.rfind('/')+1]
  201.                                 newName = "%s%s/" % (newName, request.POST.get('name'))
  202.                         #Update any filesharing information
  203.                         shared = FileShares.objects.filter(path=path)
  204.                         for share in shared:
  205.                                 share.path = newName
  206.                                 share.save()
  207.                         #Alter the contents of the folder
  208.                         FileUtils._move_folder(self, path, newName)
  209.                 #Get the parent to return it's contents
  210.                 if FileUtils.is_file(path):
  211.                         parent = path[:path.rfind('/') + 1]
  212.                 elif FileUtils.is_folder(path):
  213.                         parent = path[:path.rfind('/')]
  214.                         parent = parent[:parent.rfind('/') + 1]
  215.                 return self.get_contents(None, parent)
  216.  
  217.         def move_file(self, oldPath, newPath):
  218.                 self.s3Bucket.copy_key(newPath, settings.S3_BUCKET, oldPath)
  219.                 self.s3Bucket.delete_key(oldPath)
  220.                 return True
  221.  
  222.         def _move_folder(self, path, name):
  223.                 """
  224.                 Recursive helper method to move folders and their containing files
  225.  
  226.                 Parameters:
  227.                         self
  228.                         path - key name for the folder to be changed
  229.                         name - new key name to replace old path
  230.                 """
  231.                 for key in self.s3Bucket.list(prefix=path, delimiter="/"):
  232.                         if FileUtils.is_file(key.name):
  233.                                 newName = "%s%s" %(name, key.name[key.name.rfind('/')+1:])
  234.                                 self.s3Bucket.copy_key(newName, settings.S3_BUCKET, key.name)
  235.                                 self.s3Bucket.delete_key(key.name)
  236.                         elif FileUtils.is_folder(key.name):
  237.                                 newFolder = key.name[:key.name.rfind('/')]
  238.                                 newFolder = "%s%s/" % (name, newFolder[newFolder.rfind('/')+1:])
  239.                                 if self.s3Bucket.get_key(key.name):
  240.                                         self.s3Bucket.copy_key(newFolder, settings.S3_BUCKET, key.name)
  241.                                         self.s3Bucket.delete_key(key.name)
  242.                                 else:
  243.                                         k = self.s3Bucket.new_key(newFolder)
  244.                                         k.set_contents_from_string("")
  245.                                 if key.name != path:
  246.                                         FileUtils._move_folder(self, key.name, newFolder)
  247.  
  248.         @staticmethod  
  249.         def is_file(path):
  250.                 """
  251.                 This method may need to become more robust in the future, but it's purpose is to detect within amazon s3 whether a given path is a file.
  252.  
  253.                 Parameters:
  254.                         path - The path of the file
  255.  
  256.                 Returns:
  257.                         true if the path is a file, otherwise false
  258.                 """
  259.                 foldername, filename = os.path.split(path)
  260.                 return filename != ''
  261.  
  262.         @staticmethod
  263.         def is_folder(path):
  264.                 """
  265.                 This method may need to become more robust in the future, but it's purpose is to detect within amazon s3 whether a given path is a folder.
  266.  
  267.                 Parameters:
  268.                         path - The path of the folder
  269.  
  270.                 Returns:
  271.                         true if the path is a folder, otherwise false
  272.                 """
  273.                 foldername, filename = os.path.split(path)
  274.                 return filename == ''
  275.  
  276.         def get_contents(self, subFolder=None, path=None):     
  277.                 """
  278.                 This method gets the file list for all files and what folder they are contained in for a given path.  It drives the recursive method that gets the contents for all folders and their subfolders.
  279.  
  280.                 Parameters:
  281.                         subFolder - The subfolder of the root directory to begin at
  282.                         path - Explicit path to get contents
  283.  
  284.                 Returns:
  285.                         A dictionary of files and folders with their contents.
  286.                 """
  287.                 contents = self._get_contents(subFolder, path)
  288.                 if path is None or path == self.rootFolder:
  289.                         #now get the shared stuff
  290.                         sharedContents = {'folders':[], 'files':[]}
  291.                         shared = FileSharesPermissions.objects.filter(company__in=[self.companyID, 0])
  292.                         for share in shared:
  293.                                 path = share.path.path
  294.                                 if path[:self.rootFolder.__len__()] == self.rootFolder:
  295.                                         continue
  296.                                 shareContents = {'folders':[], 'files':[]}
  297.                                 for key in self.s3Bucket.list(prefix=path, delimiter="/"):
  298.                                         if key.name.startswith("."):
  299.                                                 continue
  300.                                         if FileUtils.is_folder(key.name):
  301.                                                 if key.name == path:
  302.                                                         continue
  303.                                                 shareContents['folders'].append({"foldername":key.name.replace(path, ""), "meta":{"size":'--', 'moddate':'--', 'fullpath':key.name}, 'contents':{'folders':[], 'files':[]}})
  304.  
  305.                                         if FileUtils.is_file(key.name):
  306.                                                 s = key.size
  307.                                                 d = datetime.datetime.strptime(key.last_modified[:19], "%Y-%m-%dT%H:%M:%S")
  308.                                                 if key.name == path:
  309.                                                         folderName, keyName = os.path.split(path)
  310.                                                 else:
  311.                                                         keyName = key.name.replace(path, "")
  312.                                                 shareContents['files'].append({"filename":keyName, "meta":{"size":FileUtils.convert_bytes(s), "moddate":d.strftime("%m/%d/%y %H:%M:%S"), 'fullpath':key.name}})
  313.                                 if FileUtils.is_folder(path):
  314.                                         sharedContents['folders'].append({'foldername':("%s/" % os.path.basename(os.path.normpath(path))), 'meta':{'size':'--', 'moddate':'--', 'fullpath':path}, 'contents':shareContents})
  315.                                 else:
  316.                                         sharedContents['files'].extend(shareContents['files'])
  317.  
  318.                         contents['folders'].append({"foldername":"SHARED/", "meta":{"size":"--", 'moddate':'--'}, 'contents':sharedContents})
  319.  
  320.                 return contents
  321.  
  322.         def _get_contents(self, subFolder=None, path=None):
  323.                 """
  324.                 This method gets the file list for all files and what folder they are contained in for a given path.  It recursively gets the contents for all folders and their subfolders.
  325.  
  326.                 Parameters:
  327.                         subFolder - The subfolder of the root directory to begin at
  328.                         path - Explicit path to get contents
  329.  
  330.                 Returns:
  331.                         A dictionary of files and folders with their contents.
  332.                 """
  333.                 if subFolder is None and path is None:
  334.                         path = self.rootFolder
  335.                 elif subFolder is not None and path is None:
  336.                         path = "%s%s/" % (self.rootFolder, subFolder)
  337.                 elif subFolder is not None and path is not None:
  338.                         path = "%s%s/" % (path, subFolder)
  339.  
  340.                 contents = {'folders':[], 'files':[]}
  341.                 for key in self.s3Bucket.list(prefix=path, delimiter="/"):
  342.                         if key.name.startswith("."):
  343.                                 continue
  344.                         if FileUtils.is_folder(key.name):
  345.                                 #Specification files will be handled by the user through the Specification Files page
  346.                                 if key.name == path or key.name == self.rootFolder + 'SPECIFICATION FILES/':
  347.                                         continue
  348.                                 contents['folders'].append({"foldername":key.name.replace(path, ""), "meta":{"size":'--', 'moddate':'--', 'fullpath':key.name}, 'contents':{'folders':[], 'files':[]}})
  349.  
  350.                         if FileUtils.is_file(key.name):
  351.                                 s = key.size
  352.                                 d = datetime.datetime.strptime(key.last_modified[:19], "%Y-%m-%dT%H:%M:%S")
  353.                                 contents['files'].append({"filename":key.name.replace(path, ""), "meta":{"size":FileUtils.convert_bytes(s), "moddate":d.strftime("%m/%d/%y %H:%M:%S"), 'fullpath':key.name}})
  354.  
  355.                 return contents
  356.  
  357.                 @staticmethod  
  358.                 def convert_bytes(bytes):              
  359.                 """            
  360.                This is a static helper method to convert bytes into a readable format
  361.                 Parameters:     bytes - Bytes to be formated
  362.                 Returns:        A string representation of the bytes in a more readable format         
  363.                """
  364.                 bytes = float(bytes)
  365.                 if bytes >= 1099511627776:
  366.                         terabytes = bytes / 1099511627776
  367.                         size = '%.2fTB' % terabytes
  368.                 elif bytes >= 1073741824:
  369.                         gigabytes = bytes / 1073741824
  370.                         size = '%.2fGB' % gigabytes
  371.                 elif bytes >= 1048576:
  372.                         megabytes = bytes / 1048576
  373.                         size = '%.2fMB' % megabytes
  374.                 elif bytes >= 1024:
  375.                         kilobytes = bytes / 1024
  376.                         size = '%.2fKB' % kilobytes
  377.                 else:
  378.                         size = '%.2fB' % bytes
  379.                 return size
RAW Paste Data
Top