Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

#!/usr/bin/env python 

# -*- coding: utf-8 -*- 

 

############################################################################### 

#  Copyright 2013 Kitware Inc. 

# 

#  Licensed under the Apache License, Version 2.0 ( the "License" ); 

#  you may not use this file except in compliance with the License. 

#  You may obtain a copy of the License at 

# 

#    http://www.apache.org/licenses/LICENSE-2.0 

# 

#  Unless required by applicable law or agreed to in writing, software 

#  distributed under the License is distributed on an "AS IS" BASIS, 

#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

#  See the License for the specific language governing permissions and 

#  limitations under the License. 

############################################################################### 

 

import cherrypy 

import datetime 

 

from girder import events 

from girder.utility import assetstore_utilities 

from .model_base import Model, ValidationException 

from ..constants import AccessType 

 

 

class Upload(Model): 

    """ 

    This model stores temporary records for uploads that have been approved 

    but are not yet complete, so that they can be uploaded in chunks of 

    arbitrary size. The chunks must be uploaded in order. 

    """ 

    def initialize(self): 

        self.name = 'upload' 

 

    def validate(self, doc): 

        if doc['size'] < 0: 

            raise ValidationException('File size must not be negative.') 

        if doc['received'] > doc['size']: 

            raise ValidationException('Received bytes must not be larger than ' 

                                      'the total size of the upload.') 

 

        doc['updated'] = datetime.datetime.now() 

 

        return doc 

 

    def handleChunk(self, upload, chunk): 

        """ 

        When a chunk is uploaded, this should be called to process the chunk. 

        If this is the final chunk of the upload, this method will finalize 

        the upload automatically. 

        :param upload: The upload document to update. 

        :type upload: dict 

        :param chunk: The file object representing the chunk that was uploaded. 

        :type chunk: file 

        """ 

        assetstore = self.model('assetstore').load(upload['assetstoreId']) 

        adapter = assetstore_utilities.getAssetstoreAdapter(assetstore) 

        upload = self.save(adapter.uploadChunk(upload, chunk)) 

 

        # If upload is finished, we finalize it 

        if upload['received'] == upload['size']: 

            return self.finalizeUpload(upload, assetstore) 

 

    def requestOffset(self, upload): 

        """ 

        Requests the offset that should be used to resume uploading. This 

        makes the request from the assetstore adapter. 

        """ 

        assetstore = self.model('assetstore').load(upload['assetstoreId']) 

        adapter = assetstore_utilities.getAssetstoreAdapter(assetstore) 

        return adapter.requestOffset(upload) 

 

    def finalizeUpload(self, upload, assetstore=None): 

        """ 

        This should only be called manually in the case of creating an 

        empty file, i.e. one that has no chunks. 

        """ 

        if assetstore is None: 

            assetstore = self.model('assetstore').load(upload['assetstoreId']) 

 

        if upload['parentType'] == 'folder': 

            # Create a new item with the name of the file. 

            item = self.model('item').createItem( 

                name=upload['name'], creator={'_id': upload['userId']}, 

                folder={'_id': upload['parentId']}) 

        else: 

            item = self.model('item').load(id=upload['parentId'], 

                                           objectId=True, 

                                           user={'_id': upload['userId']}, 

                                           level=AccessType.WRITE) 

 

        file = self.model('file').createFile( 

            item=item, name=upload['name'], size=upload['size'], 

            creator={'_id': upload['userId']}, assetstore=assetstore, 

            mimeType=upload['mimeType']) 

 

        adapter = assetstore_utilities.getAssetstoreAdapter(assetstore) 

        file = adapter.finalizeUpload(upload, file) 

        self.model('file').save(file) 

        self.remove(upload) 

 

        # Add an async event for handlers that wish to process this file. 

        events.daemon.trigger('data.process', { 

            'file': file, 

            'assetstore': assetstore 

        }) 

 

        return file 

 

    def createUpload(self, user, name, parentType, parent, size, mimeType): 

        """ 

        Creates a new upload record, and creates its temporary file 

        that the chunks will be written into. Chunks should then be sent 

        in order using the _id of the upload document generated by this method. 

 

        :param user: The user performing the upload. 

        :type user: dict 

        :param name: The name of the file being uploaded. 

        :type name: str 

        :param parentType: The type of the parent being uploaded into. 

        :type parentType: str ('folder' or 'item') 

        :param parent: The document representing the parent. 

        :type parentId: dict 

        :param size: Total size in bytes of the whole file. 

        :type size: int 

        :param mimeType: The mimeType of the file. 

        :type mimeType: str 

        :returns: The upload document that was created. 

        """ 

        assetstore = self.model('assetstore').getCurrent() 

        adapter = assetstore_utilities.getAssetstoreAdapter(assetstore) 

        now = datetime.datetime.now() 

 

        upload = { 

            'created': now, 

            'updated': now, 

            'userId': user['_id'], 

            'parentType': parentType.lower(), 

            'parentId': parent['_id'], 

            'assetstoreId': assetstore['_id'], 

            'size': size, 

            'name': name, 

            'mimeType': mimeType, 

            'received': 0 

        } 

        upload = adapter.initUpload(upload) 

        return self.save(upload)