store_api.py 6.71 KB
Newer Older
Bach Dániel committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.

18
from os.path import splitext
Guba Sándor committed
19
import json
20
import logging
Őry Máté committed
21
from urlparse import urljoin
Kálmán Viktor committed
22 23
from datetime import datetime

Őry Máté committed
24
from django.http import Http404
25
from django.conf import settings
Őry Máté committed
26
from requests import get, post, codes
27
from requests.exceptions import Timeout  # noqa
Őry Máté committed
28
from sizefield.utils import filesizeformat
Guba Sándor committed
29

30 31
logger = logging.getLogger(__name__)

Guba Sándor committed
32

Őry Máté committed
33
class StoreApiException(Exception):
34 35 36
    pass


Őry Máté committed
37 38 39 40 41 42
class NotOkException(StoreApiException):
    def __init__(self, status, *args, **kwargs):
        self.status = status
        super(NotOkException, self).__init__(*args, **kwargs)


43 44 45 46
class NoStoreException(StoreApiException):
    pass


47 48 49 50
class NoOrgIdException(StoreApiException):
    pass


Őry Máté committed
51 52 53
class Store(object):

    def __init__(self, user, default_timeout=0.5):
54 55 56 57 58
        self.store_url = settings.STORE_URL
        if not self.store_url:
            raise NoStoreException
        if not user.profile.org_id:
            raise NoOrgIdException
59
        self.username = 'u-%s' % user.profile.org_id
Őry Máté committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73
        self.request_args = {'verify': settings.STORE_VERIFY_SSL}
        if settings.STORE_SSL_AUTH:
            self.request_args['cert'] = (settings.STORE_CLIENT_CERT,
                                         settings.STORE_CLIENT_KEY)
        if settings.STORE_BASIC_AUTH:
            self.request_args['auth'] = (settings.STORE_CLIENT_USER,
                                         settings.STORE_CLIENT_PASSWORD)
        self.default_timeout = default_timeout

    def _request(self, url, method=get, timeout=None,
                 raise_status_code=True, **kwargs):
        url = urljoin(self.store_url, url)
        if timeout is None:
            timeout = self.default_timeout
74 75
        kwargs['USER'] = self.username
        payload = json.dumps(kwargs)
Őry Máté committed
76 77 78 79 80 81 82 83
        try:
            headers = {'content-type': 'application/json'}
            response = method(url, data=payload, headers=headers,
                              timeout=timeout, **self.request_args)
        except Exception:
            logger.exception("Error in store %s loading %s",
                             unicode(method), url)
            raise
Kálmán Viktor committed
84
        else:
Őry Máté committed
85 86 87 88 89 90 91 92
            if raise_status_code and response.status_code != codes.ok:
                if response.status_code == 404:
                    raise Http404()
                else:
                    raise NotOkException(response.status_code)
            return response

    def _request_cmd(self, cmd, **kwargs):
93
        return self._request("/user/", post, CMD=cmd, **kwargs)
Őry Máté committed
94 95 96 97 98 99 100 101

    def list(self, path, process=True):
        r = self._request_cmd("LIST", PATH=path)
        result = r.json()
        if process:
            return self._process_list(result)
        else:
            return result
Kálmán Viktor committed
102

Őry Máté committed
103 104 105 106 107 108 109 110 111
    def toplist(self, process=True):
        r = self._request_cmd("TOPLIST")
        result = r.json()
        if process:
            return self._process_list(result)
        else:
            return result

    def request_download(self, path):
112 113
        r = self._request_cmd("DOWNLOAD", PATH=path, timeout=10)
        return r.json()['LINK']
Őry Máté committed
114 115

    def request_upload(self, path):
116 117
        r = self._request_cmd("UPLOAD", PATH=path)
        return r.json()['LINK']
Őry Máté committed
118 119 120 121 122 123 124 125 126 127 128

    def remove(self, path):
        self._request_cmd("REMOVE", PATH=path)

    def new_folder(self, path):
        self._request_cmd("NEW_FOLDER", PATH=path)

    def rename(self, old_path, new_name):
        self._request_cmd("RENAME", PATH=old_path, NEW_NAME=new_name)

    def get_quota(self):  # no CMD? :o
129
        r = self._request("/user/")
130 131
        quota = r.json()
        quota.update({
Guba Sándor committed
132 133 134
            'readable_used': filesizeformat(float(quota['used'])),
            'readable_soft': filesizeformat(float(quota['soft'])),
            'readable_hard': filesizeformat(float(quota['hard'])),
135 136
        })
        return quota
Őry Máté committed
137 138

    def set_quota(self, quota):
139
        self._request("/quota/", post, QUOTA=quota)
Őry Máté committed
140 141 142

    def user_exist(self):
        try:
143
            self._request("/user/")
Őry Máté committed
144 145 146 147 148
            return True
        except NotOkException:
            return False

    def create_user(self, password, keys, quota):
149
        self._request("/new/", method=post,
150
                      SMBPASSWD=password, KEYS=keys, QUOTA=quota)
Őry Máté committed
151 152 153 154 155 156 157 158 159 160 161 162 163

    @staticmethod
    def _process_list(content):
        for d in content:
            d['human_readable_date'] = datetime.utcfromtimestamp(float(
                d['MTIME']))
            delta = (datetime.utcnow() -
                     d['human_readable_date']).total_seconds()
            d['is_new'] = 0 < delta < 5
            d['human_readable_size'] = (
                "directory" if d['TYPE'] == "D" else
                filesizeformat(float(d['SIZE'])))

164
            if d['DIR'] == ".":
Őry Máté committed
165 166 167 168 169 170 171 172 173
                d['directory'] = "/"
            else:
                d['directory'] = "/" + d['DIR'] + "/"

            d['path'] = d['directory']
            d['path'] += d['NAME']
            if d['TYPE'] == "D":
                d['path'] += "/"

174
            d['ext'] = splitext(d['path'])[1]
175
            d['icon'] = ("folder-open" if not d['TYPE'] == "F"
176 177
                         else file_icons.get(d['ext'], "file-o"))

Őry Máté committed
178
        return sorted(content, key=lambda k: k['TYPE'])
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220


file_icons = {
    '.txt': "file-text-o",
    '.pdf': "file-pdf-o",

    '.jpg': "file-image-o",
    '.jpeg': "file-image-o",
    '.png': "file-image-o",
    '.gif': "file-image-o",

    '.avi': "file-video-o",
    '.mkv': "file-video-o",
    '.mp4': "file-video-o",
    '.mov': "file-video-o",

    '.mp3': "file-sound-o",
    '.flac': "file-sound-o",
    '.wma': "file-sound-o",

    '.pptx': "file-powerpoint-o",
    '.ppt': "file-powerpoint-o",
    '.doc': "file-word-o",
    '.docx': "file-word-o",
    '.xlsx': "file-excel-o",
    '.xls': "file-excel-o",

    '.rar': "file-archive-o",
    '.zip': "file-archive-o",
    '.7z': "file-archive-o",
    '.tar': "file-archive-o",
    '.gz': "file-archive-o",

    '.py': "file-code-o",
    '.html': "file-code-o",
    '.js': "file-code-o",
    '.css': "file-code-o",
    '.c': "file-code-o",
    '.cpp': "file-code-o",
    '.h': "file-code-o",
    '.sh': "file-code-o",
}