Skip to content
This repository has been archived by the owner on Jul 30, 2019. It is now read-only.

adimian/haruba

Repository files navigation

****************
* User section *
****************

Introduction
============

Haruba is an api that allows you to interact with a filesystem on a remote server
It defines zones that each act as an independant filesystem.

For these zones you can define permissions. Permissions are driven by the sigil api.

In this readme we will also provide python examples of how to make calls.
For each example we will assume the following is defined

Code
----

import requests
session = requests.Session()
proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}
session.proxies = proxies
base_url = "http://haruba.com"

Login
=====

Logging in will allow you to interact with the application. When logging in
you will be provided with cookies. It's essential that you provide these
cookies every time you make a consequent call.

Url
---

<base_url>/login

Allowed request methods
-----------------------

GET: will tell you if you are loggin in or not
- params: None
- returns: True/False

example:
url = "%s/login" % base_url
session.request('get', url)

POST: making a post request will allow you to log in with either your login/password combination or your api key.
- params:
  * login: the user login
  * password: the user password
  * (not implemented yet) api key: the api key of the user
- return type: JSON
- returns: {"message": <string>}
- error returns: {"message": <string>}

example:
url = "%s/login" % base_url
session.request('post', url, data={'login': 'myuser',
								   'password': 'mypassword'})



My zones
========

Haruba maps real filesystem paths to "zones". A Zone is like an Amazon S3 bucket or a separate hard drive.
All Folders belong to a Zone, Files in turn are located in Folders. Folders can contain other Folders as well.
With this url you are able to see the zones you are allowed to interact with.

Url
---

<base_url>/myzones

Allowed request methods
-----------------------
GET: returns a list of allowed zones and the access right you have
- data params: None
- JSON params: None
- return type: JSON
- returns: [{"zone": <zone>, "access": [<string:read>, <string:write>]}, {...}]
- error returns: {"message": "<string>"}

example:
url = "%s/myzones" % base_url
session.request('get', url)


Folder
======

The folder url will allow you to interact with a given path.

Url
---

<base_url>/files/<zone> # zone root
<base_url>/files/<zone>/<path> # deeper into the zone

Allowed request methods
-----------------------

GET: will assemble a list of current directories and files at the current location.
- data params: None
- JSON params: None
- return type: JSON
- returns: [{'name': <string>,
             'is_file': <boolean>,
             'is_dir': <boolean>,
             'size': <int>,
             'modif_date': <string:%Y-%m-%d %H:%M:%S>}, 
            {...},
            {...}]
- error returns: {"message": "<string>"}

example:
url = "%s/files/my_zone/myfolder1" % base_url
session.request('get', url)

POST: will create a folder at a given path.
- data params: None
- JSON params: None
- return type: JSON
- returns: {"message": <string>}
- error returns: {"message": <string>}

example:
url = "%s/files/my_zone/myfolder1/my_new_folder" % base_url
session.request('post', url)

PUT: will rename a folder or file at a given path
- data params: 
  * rename_to: <string> #the file or folder will be renamed to this value
- JSON params: None
- return type: JSON
- returns: {"message": <string>}
- error returns: {"message": <string>}

example:
url = "%s/files/my_zone/myfolder1/my_old_folder" % base_url
payload = {'rename_to': 'my_new_named_folder'}
session.request('put', url, data=payload)

DELETE: deletes if the given path is a file
        if the given path is a folder, it will check for request data
        if there is data, the files given in the data will be deleted
        if there is no data, the folder is deleted.
- data params: None
- JSON params: 
  * (optional) file_to_delete: [<string>, <string>] # a list of filenames at the given path to delete.
  WARNING: Make sure to set the 'content_type' header to 'application/json'. Or you will delete your folder
- return type: JSON
- returns: {"message": <string>}
- error returns: {"message": <string>}

example:
# delete the whole folder
url = "%s/files/my_zone/myfolder1/my_to_delete_folder" % base_url
session.request('delete', url)

# delete a specific file
url = "%s/files/my_zone/myfolder1/my_to_delete_file" % base_url
session.request('delete', url)

# delete the specific files in the folder
url = "%s/files/my_zone/myfolder1/my_to_delete_folder" % base_url
payload = {'files_to_delete': ['some_file', 'another_file']}
session.request('delete', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header


Upload
======

Allows you to upload files to a given path

Url
---
<base_url>/upload/<zone>
<base_url>/upload/<zone>/<path>

Allowed request methods
-----------------------
POST: uploads the given files to the given path, the path must be a folder
- data params: 
  * (optional) unpack_zip: <boolean> # if the uploaded files contain a zip, it will unpack the zip if set to true. zip files must end with '.zip'
  * (optional) delete_zip_after_unpack: <boolean> # will remove the uploaded zip after unpacking if set to true.
- JSON params: None
- File params: 
  * files: [("files", <file1>), ("files", <file2>)] # list of files to upload
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/upload/my_zone/myfolder1" % base_url
files = [("files", open('/path/to/file.txt', 'rb')),
		 ("files", open('/path/to/file.zip', 'rb'))]
payload = {'unpack_zip': True,
		   'delete_zip_after_unpack': True}
session.request('post', url, files=files, data=payload)


Download
========

Allows you to download files from a given path

Url
---
<base_url>/download/<zone>
<base_url>/download/<zone>/<path>

Allowed request methods
-----------------------
GET: downloads the file or folder (zip) at the given path
- data params: None
- JSON params: None
- return type: File
- returns: <file>
- error returns: {"message": "<string>"}

example:
url = "%s/download/my_zone/myfolder1/myfile" % base_url
session.request('get', url)

POST: downloads specific files from the given path as a zip
- data params: 
  * filenames: [<file>, <file>] # list of files to download
- JSON params: None
- return type: File
- returns: <file>
- error returns: {"message": "<string>"}

example:
url = "%s/download/my_zone/myfolder1" % base_url
payload = {'filenames': ['file1.txt', 'file2.jpg']}
session.request('post', url, data=payload)

Commands
========

Commands let you interact with files and folders on a higher level.
Current command include: Copy, Cut and unzip

Url
---

<base_url>/command/<zone>
<base_url>/command/<zone>/<path>

Allowed request methods
-----------------------

POST: 
- data params: None
- JSON params:
  * commands:   [{'type': 'cut',
		          'from': ["/<zone>/some/folder",
		                   "/<zone>/another/folder"],
		          'to': "/<zone>/destination/folder"},
		         {'type': 'copy',
		          'from': ["/<zone>/yet_another/folder"],
		          'to': "/<zone>/another_destination/folder"},
		         {'type': 'unzip',
		          'delete_zip_after_unpack': True}]
  WARNING: Make sure to set the 'content_type' header to 'application/json'
  NOTE: Depending on which command you want to execute, you can assemble your commands list as you want. each 'type' is able to be used individually or combined.
  NOTE: the 'to' key is optional. if not provided, the current url path will be used to fill this key.
  NOTE: files and folders can be copied to other zones, provided you have the rights.
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/command/myzone/myfolder1" % base_url
payload = {'commands': [{'type': 'cut',
			            'from': ["/myzone/some/folder",
			                     "/myzone/another/folder"],
			            'to': "/myzone/destination/folder"}]
		  }
session.request('post', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header

*****************
* Admin section *
*****************

Zones
=====

Zones lets you be able to view, create or update zones

Url
---

<base_url>/zone

Allowed request methods
-----------------------
GET: returns a list of all zones
- data params: None
- JSON params: None
- return type: JSON
- returns: [{'id': <int>,
             'name': <string>,
             'path': <string>},
            {...}]
- error returns: {"message": "<string>"}

example:
url = "%s/zone" % base_url
session.request('get', url)

POST: Creates a single zone or a set of zones
- data params: None
- JSON params: 
  * zones: [{'zone': <zone_name>,
             'path': <path_extension>},
            {'zone': <zone_name>,
             'path': <path_extension>},
            {...}]
  WARNING: Make sure to set the 'content_type' header to 'application/json'
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/zone" % base_url
payload = [{'zone': 'my_first_zone',
             'path': ''}, # this zone will load the root of the haruba filesystem
            {'zone': 'my_second_zone',
             'path': '/my_project/data'}] # this zone will load '/my_project/data' from the root of the haruba filesystem 
                                          # (so if the haruba filesystem root is /srv/haruba, it will load /srv/haruba/my_project/data)
session.request('post', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header

PUT: Edits a single zone or a set of zones. Only the path is editable.
- data params:
- JSON params:
  * zones: [{'id': <zone_id>,
             'zone': <zone_name>,
             'path': <path_extension>},
            {...},]
  NOTE: You are allowed to provide both 'id' and 'zone' key but both are also optional, as long as their counterpart is provided.
  * copy_contents: <boolean> # Moves the old path to the new path if set to true, 
  							 # if multiple zones depend on the old path, a copy is made instead. 
  							 # Makes an empty folder at the new path if set to false
  * adopt_if_exists: <boolean> # Adopts the new path if it already exists on the server if set to true.
  							   # Will throw an error if the new path already exists if set to false.
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/zone" % base_url
payload = [{'id': 1,
             'path': '/my_new_path'},
            {'zone': 'my_second_zone',
             'path': '/my_newer_path'}]
session.request('put', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header


Permissions
===========

Lets you define user permissions for the existing zones.
Current permissions are 'read' and 'write'

Url
---

<base_url>/permissions

Allowed request methods
-----------------------
GET: returns a list of all users and their permissions
- data params: None
- JSON params: None
- return type: JSON
- returns: [{<user data key>: <user data>,
			 'permissions': {'<zone>': ['<permission>', '<permission>'],
			                 '<zone>': ['<permission>']}
			}]
- error returns: {"message": "<string>"}

example:
url = "%s/permissions" % base_url
session.request('get', url)

POST: grants a set of permissions
- data params: None
- JSON params:
  * permissions: [{'username': '<username>',
                   'needs': [['zone', '<permission>', '<zone>'], 
                             ['zone', '<permission>', '<zone>']]}
                 ]
  WARNING: Make sure to set the 'content_type' header to 'application/json'
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/permissions" % base_url
payload = {'permissions': [{'username': 'my_username',
                   			'needs': [['zone', 'read', 'my_first_zone'], 
                             		  ['zone', 'write', 'my_first_zone'],
                             		  ['zone', 'read', 'my_second_zone'],
                             		 ]}
                 		  ]}
session.request('post', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header

DELETE: revokes a set of permissions
- data params: None
- JSON params: 
  * permissions: [{'username': '<username>',
                   'needs': [['zone', '<permission>', '<zone>'], 
                             ['zone', '<permission>', '<zone>']]}
                 ]
  WARNING: Make sure to set the 'content_type' header to 'application/json'
- return type: JSON
- returns: {"message": "<string>"}
- error returns: {"message": "<string>"}

example:
url = "%s/permissions" % base_url
payload = {'permissions': [{'username': 'my_username',
                   			'needs': [['zone', 'read', 'my_first_zone'], 
                             		  ['zone', 'write', 'my_first_zone'],
                             		  ['zone', 'read', 'my_second_zone'],
                             		 ]}
                 		  ]}
session.request('delete', url, json=payload)
# notice how we're using 'json' instead of 'data' to enforce the content-type header