1# -------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for
4# license information.
5# --------------------------------------------------------------------------
6# pylint: disable=too-few-public-methods, too-many-instance-attributes
7# pylint: disable=super-init-not-called, too-many-lines
8
9from azure.core.paging import PageIterator
10from ._parser import _parse_datetime_from_str
11from ._shared.response_handlers import return_context_and_deserialized, process_storage_error
12from ._shared.models import DictMixin, get_enum_value
13from ._generated.models import StorageErrorException
14from ._generated.models import Metrics as GeneratedMetrics
15from ._generated.models import RetentionPolicy as GeneratedRetentionPolicy
16from ._generated.models import CorsRule as GeneratedCorsRule
17from ._generated.models import AccessPolicy as GenAccessPolicy
18from ._generated.models import DirectoryItem
19
20
21def _wrap_item(item):
22    if isinstance(item, DirectoryItem):
23        return {'name': item.name, 'is_directory': True}
24    return {'name': item.name, 'size': item.properties.content_length, 'is_directory': False}
25
26
27class Metrics(GeneratedMetrics):
28    """A summary of request statistics grouped by API in hour or minute aggregates
29    for files.
30
31    All required parameters must be populated in order to send to Azure.
32
33    :keyword str version: The version of Storage Analytics to configure.
34    :keyword bool enabled: Required. Indicates whether metrics are enabled for the
35        File service.
36    :keyword bool include_ap_is: Indicates whether metrics should generate summary
37        statistics for called API operations.
38    :keyword ~azure.storage.fileshare.RetentionPolicy retention_policy: Determines how long the associated data should
39        persist.
40    """
41
42    def __init__(self, **kwargs):
43        self.version = kwargs.get('version', u'1.0')
44        self.enabled = kwargs.get('enabled', False)
45        self.include_apis = kwargs.get('include_apis')
46        self.retention_policy = kwargs.get('retention_policy') or RetentionPolicy()
47
48    @classmethod
49    def _from_generated(cls, generated):
50        if not generated:
51            return cls()
52        return cls(
53            version=generated.version,
54            enabled=generated.enabled,
55            include_apis=generated.include_apis,
56            retention_policy=RetentionPolicy._from_generated(generated.retention_policy)  # pylint: disable=protected-access
57        )
58
59
60class RetentionPolicy(GeneratedRetentionPolicy):
61    """The retention policy which determines how long the associated data should
62    persist.
63
64    All required parameters must be populated in order to send to Azure.
65
66    :param bool enabled: Required. Indicates whether a retention policy is enabled
67        for the storage service.
68    :param int days: Indicates the number of days that metrics or logging or
69        soft-deleted data should be retained. All data older than this value will
70        be deleted.
71    """
72
73    def __init__(self, enabled=False, days=None):
74        self.enabled = enabled
75        self.days = days
76        if self.enabled and (self.days is None):
77            raise ValueError("If policy is enabled, 'days' must be specified.")
78
79    @classmethod
80    def _from_generated(cls, generated):
81        if not generated:
82            return cls()
83        return cls(
84            enabled=generated.enabled,
85            days=generated.days,
86        )
87
88
89class CorsRule(GeneratedCorsRule):
90    """CORS is an HTTP feature that enables a web application running under one
91    domain to access resources in another domain. Web browsers implement a
92    security restriction known as same-origin policy that prevents a web page
93    from calling APIs in a different domain; CORS provides a secure way to
94    allow one domain (the origin domain) to call APIs in another domain.
95
96    All required parameters must be populated in order to send to Azure.
97
98    :param list(str) allowed_origins:
99        A list of origin domains that will be allowed via CORS, or "*" to allow
100        all domains. The list of must contain at least one entry. Limited to 64
101        origin domains. Each allowed origin can have up to 256 characters.
102    :param list(str) allowed_methods:
103        A list of HTTP methods that are allowed to be executed by the origin.
104        The list of must contain at least one entry. For Azure Storage,
105        permitted methods are DELETE, GET, HEAD, MERGE, POST, OPTIONS or PUT.
106    :keyword list(str) allowed_headers:
107        Defaults to an empty list. A list of headers allowed to be part of
108        the cross-origin request. Limited to 64 defined headers and 2 prefixed
109        headers. Each header can be up to 256 characters.
110    :keyword list(str) exposed_headers:
111        Defaults to an empty list. A list of response headers to expose to CORS
112        clients. Limited to 64 defined headers and two prefixed headers. Each
113        header can be up to 256 characters.
114    :keyword int max_age_in_seconds:
115        The number of seconds that the client/browser should cache a
116        preflight response.
117    """
118
119    def __init__(self, allowed_origins, allowed_methods, **kwargs):
120        self.allowed_origins = ','.join(allowed_origins)
121        self.allowed_methods = ','.join(allowed_methods)
122        self.allowed_headers = ','.join(kwargs.get('allowed_headers', []))
123        self.exposed_headers = ','.join(kwargs.get('exposed_headers', []))
124        self.max_age_in_seconds = kwargs.get('max_age_in_seconds', 0)
125
126    @classmethod
127    def _from_generated(cls, generated):
128        return cls(
129            [generated.allowed_origins],
130            [generated.allowed_methods],
131            allowed_headers=[generated.allowed_headers],
132            exposed_headers=[generated.exposed_headers],
133            max_age_in_seconds=generated.max_age_in_seconds,
134        )
135
136
137class AccessPolicy(GenAccessPolicy):
138    """Access Policy class used by the set and get acl methods in each service.
139
140    A stored access policy can specify the start time, expiry time, and
141    permissions for the Shared Access Signatures with which it's associated.
142    Depending on how you want to control access to your resource, you can
143    specify all of these parameters within the stored access policy, and omit
144    them from the URL for the Shared Access Signature. Doing so permits you to
145    modify the associated signature's behavior at any time, as well as to revoke
146    it. Or you can specify one or more of the access policy parameters within
147    the stored access policy, and the others on the URL. Finally, you can
148    specify all of the parameters on the URL. In this case, you can use the
149    stored access policy to revoke the signature, but not to modify its behavior.
150
151    Together the Shared Access Signature and the stored access policy must
152    include all fields required to authenticate the signature. If any required
153    fields are missing, the request will fail. Likewise, if a field is specified
154    both in the Shared Access Signature URL and in the stored access policy, the
155    request will fail with status code 400 (Bad Request).
156
157    :param permission:
158        The permissions associated with the shared access signature. The
159        user is restricted to operations allowed by the permissions.
160        Required unless an id is given referencing a stored access policy
161        which contains this field. This field must be omitted if it has been
162        specified in an associated stored access policy.
163    :type permission: str or ~azure.storage.fileshare.FileSasPermissions or
164        ~azure.storage.fileshare.ShareSasPermissions
165    :param expiry:
166        The time at which the shared access signature becomes invalid.
167        Required unless an id is given referencing a stored access policy
168        which contains this field. This field must be omitted if it has
169        been specified in an associated stored access policy. Azure will always
170        convert values to UTC. If a date is passed in without timezone info, it
171        is assumed to be UTC.
172    :type expiry: ~datetime.datetime or str
173    :param start:
174        The time at which the shared access signature becomes valid. If
175        omitted, start time for this call is assumed to be the time when the
176        storage service receives the request. Azure will always convert values
177        to UTC. If a date is passed in without timezone info, it is assumed to
178        be UTC.
179    :type start: ~datetime.datetime or str
180    """
181    def __init__(self, permission=None, expiry=None, start=None):
182        self.start = start
183        self.expiry = expiry
184        self.permission = permission
185
186
187class LeaseProperties(DictMixin):
188    """File Lease Properties.
189
190    :ivar str status:
191        The lease status of the file. Possible values: locked|unlocked
192    :ivar str state:
193        Lease state of the file. Possible values: available|leased|expired|breaking|broken
194    :ivar str duration:
195        When a file is leased, specifies whether the lease is of infinite or fixed duration.
196    """
197
198    def __init__(self, **kwargs):
199        self.status = get_enum_value(kwargs.get('x-ms-lease-status'))
200        self.state = get_enum_value(kwargs.get('x-ms-lease-state'))
201        self.duration = get_enum_value(kwargs.get('x-ms-lease-duration'))
202
203    @classmethod
204    def _from_generated(cls, generated):
205        lease = cls()
206        lease.status = get_enum_value(generated.properties.lease_status)
207        lease.state = get_enum_value(generated.properties.lease_state)
208        lease.duration = get_enum_value(generated.properties.lease_duration)
209        return lease
210
211
212class ContentSettings(DictMixin):
213    """Used to store the content settings of a file.
214
215    :param str content_type:
216        The content type specified for the file. If no content type was
217        specified, the default content type is application/octet-stream.
218    :param str content_encoding:
219        If the content_encoding has previously been set
220        for the file, that value is stored.
221    :param str content_language:
222        If the content_language has previously been set
223        for the file, that value is stored.
224    :param str content_disposition:
225        content_disposition conveys additional information about how to
226        process the response payload, and also can be used to attach
227        additional metadata. If content_disposition has previously been set
228        for the file, that value is stored.
229    :param str cache_control:
230        If the cache_control has previously been set for
231        the file, that value is stored.
232    :param str content_md5:
233        If the content_md5 has been set for the file, this response
234        header is stored so that the client can check for message content
235        integrity.
236    """
237
238    def __init__(
239            self, content_type=None, content_encoding=None,
240            content_language=None, content_disposition=None,
241            cache_control=None, content_md5=None, **kwargs):
242
243        self.content_type = content_type or kwargs.get('Content-Type')
244        self.content_encoding = content_encoding or kwargs.get('Content-Encoding')
245        self.content_language = content_language or kwargs.get('Content-Language')
246        self.content_md5 = content_md5 or kwargs.get('Content-MD5')
247        self.content_disposition = content_disposition or kwargs.get('Content-Disposition')
248        self.cache_control = cache_control or kwargs.get('Cache-Control')
249
250    @classmethod
251    def _from_generated(cls, generated):
252        settings = cls()
253        settings.content_type = generated.properties.content_type or None
254        settings.content_encoding = generated.properties.content_encoding or None
255        settings.content_language = generated.properties.content_language or None
256        settings.content_md5 = generated.properties.content_md5 or None
257        settings.content_disposition = generated.properties.content_disposition or None
258        settings.cache_control = generated.properties.cache_control or None
259        return settings
260
261
262class ShareProperties(DictMixin):
263    """Share's properties class.
264
265    :ivar str name:
266        The name of the share.
267    :ivar ~datetime.datetime last_modified:
268        A datetime object representing the last time the share was modified.
269    :ivar str etag:
270        The ETag contains a value that you can use to perform operations
271        conditionally.
272    :ivar int quota:
273        The allocated quota.
274    :ivar dict metadata: A dict with name_value pairs to associate with the
275        share as metadata.
276    :ivar str snapshot:
277        Snapshot of the share.
278    """
279
280    def __init__(self, **kwargs):
281        self.name = None
282        self.last_modified = kwargs.get('Last-Modified')
283        self.etag = kwargs.get('ETag')
284        self.quota = kwargs.get('x-ms-share-quota')
285        self.next_allowed_quota_downgrade_time = kwargs.get('x-ms-share-next-allowed-quota-downgrade-time')
286        self.metadata = kwargs.get('metadata')
287        self.snapshot = None
288        self.provisioned_egress_mbps = kwargs.get('x-ms-share-provisioned-egress-mbps')
289        self.provisioned_ingress_mbps = kwargs.get('x-ms-share-provisioned-ingress-mbps')
290        self.provisioned_iops = kwargs.get('x-ms-share-provisioned-iops')
291
292    @classmethod
293    def _from_generated(cls, generated):
294        props = cls()
295        props.name = generated.name
296        props.last_modified = generated.properties.last_modified
297        props.etag = generated.properties.etag
298        props.quota = generated.properties.quota
299        props.next_allowed_quota_downgrade_time = generated.properties.next_allowed_quota_downgrade_time
300        props.metadata = generated.metadata
301        props.snapshot = generated.snapshot
302        props.provisioned_egress_mbps = generated.properties.provisioned_egress_mbps
303        props.provisioned_ingress_mbps = generated.properties.provisioned_ingress_mbps
304        props.provisioned_iops = generated.properties.provisioned_iops
305        return props
306
307
308class SharePropertiesPaged(PageIterator):
309    """An iterable of Share properties.
310
311    :ivar str service_endpoint: The service URL.
312    :ivar str prefix: A file name prefix being used to filter the list.
313    :ivar str marker: The continuation token of the current page of results.
314    :ivar int results_per_page: The maximum number of results retrieved per API call.
315    :ivar str continuation_token: The continuation token to retrieve the next page of results.
316    :ivar str location_mode: The location mode being used to list results. The available
317        options include "primary" and "secondary".
318    :ivar current_page: The current page of listed results.
319    :vartype current_page: list(~azure.storage.fileshare.ShareProperties)
320
321    :param callable command: Function to retrieve the next page of items.
322    :param str prefix: Filters the results to return only shares whose names
323        begin with the specified prefix.
324    :param int results_per_page: The maximum number of share names to retrieve per
325        call.
326    :param str continuation_token: An opaque continuation token.
327    """
328    def __init__(self, command, prefix=None, results_per_page=None, continuation_token=None):
329        super(SharePropertiesPaged, self).__init__(
330            get_next=self._get_next_cb,
331            extract_data=self._extract_data_cb,
332            continuation_token=continuation_token or ""
333        )
334        self._command = command
335        self.service_endpoint = None
336        self.prefix = prefix
337        self.marker = None
338        self.results_per_page = results_per_page
339        self.location_mode = None
340        self.current_page = []
341
342    def _get_next_cb(self, continuation_token):
343        try:
344            return self._command(
345                marker=continuation_token or None,
346                maxresults=self.results_per_page,
347                prefix=self.prefix,
348                cls=return_context_and_deserialized,
349                use_location=self.location_mode)
350        except StorageErrorException as error:
351            process_storage_error(error)
352
353    def _extract_data_cb(self, get_next_return):
354        self.location_mode, self._response = get_next_return
355        self.service_endpoint = self._response.service_endpoint
356        self.prefix = self._response.prefix
357        self.marker = self._response.marker
358        self.results_per_page = self._response.max_results
359        self.current_page = [ShareProperties._from_generated(i) for i in self._response.share_items]  # pylint: disable=protected-access
360        return self._response.next_marker or None, self.current_page
361
362
363class Handle(DictMixin):
364    """A listed Azure Storage handle item.
365
366    All required parameters must be populated in order to send to Azure.
367
368    :keyword str handle_id: Required. XSMB service handle ID
369    :keyword str path: Required. File or directory name including full path starting
370     from share root
371    :keyword str file_id: Required. FileId uniquely identifies the file or
372     directory.
373    :keyword str parent_id: ParentId uniquely identifies the parent directory of the
374     object.
375    :keyword str session_id: Required. SMB session ID in context of which the file
376     handle was opened
377    :keyword str client_ip: Required. Client IP that opened the handle
378    :keyword ~datetime.datetime open_time: Required. Time when the session that previously opened
379     the handle has last been reconnected. (UTC)
380    :keyword ~datetime.datetime last_reconnect_time: Time handle was last connected to (UTC)
381    """
382
383    def __init__(self, **kwargs):
384        self.id = kwargs.get('handle_id')
385        self.path = kwargs.get('path')
386        self.file_id = kwargs.get('file_id')
387        self.parent_id = kwargs.get('parent_id')
388        self.session_id = kwargs.get('session_id')
389        self.client_ip = kwargs.get('client_ip')
390        self.open_time = kwargs.get('open_time')
391        self.last_reconnect_time = kwargs.get('last_reconnect_time')
392
393    @classmethod
394    def _from_generated(cls, generated):
395        handle = cls()
396        handle.id = generated.handle_id
397        handle.path = generated.path
398        handle.file_id = generated.file_id
399        handle.parent_id = generated.parent_id
400        handle.session_id = generated.session_id
401        handle.client_ip = generated.client_ip
402        handle.open_time = generated.open_time
403        handle.last_reconnect_time = generated.last_reconnect_time
404        return handle
405
406
407class HandlesPaged(PageIterator):
408    """An iterable of Handles.
409
410    :ivar str marker: The continuation token of the current page of results.
411    :ivar int results_per_page: The maximum number of results retrieved per API call.
412    :ivar str continuation_token: The continuation token to retrieve the next page of results.
413    :ivar str location_mode: The location mode being used to list results. The available
414        options include "primary" and "secondary".
415    :ivar current_page: The current page of listed results.
416    :vartype current_page: list(~azure.storage.fileshare.Handle)
417
418    :param callable command: Function to retrieve the next page of items.
419    :param int results_per_page: The maximum number of share names to retrieve per
420        call.
421    :param str continuation_token: An opaque continuation token.
422    """
423    def __init__(self, command, results_per_page=None, continuation_token=None):
424        super(HandlesPaged, self).__init__(
425            get_next=self._get_next_cb,
426            extract_data=self._extract_data_cb,
427            continuation_token=continuation_token or ""
428        )
429        self._command = command
430        self.marker = None
431        self.results_per_page = results_per_page
432        self.location_mode = None
433        self.current_page = []
434
435    def _get_next_cb(self, continuation_token):
436        try:
437            return self._command(
438                marker=continuation_token or None,
439                maxresults=self.results_per_page,
440                cls=return_context_and_deserialized,
441                use_location=self.location_mode)
442        except StorageErrorException as error:
443            process_storage_error(error)
444
445    def _extract_data_cb(self, get_next_return):
446        self.location_mode, self._response = get_next_return
447        self.current_page = [Handle._from_generated(h) for h in self._response.handle_list]  # pylint: disable=protected-access
448        return self._response.next_marker or None, self.current_page
449
450
451class DirectoryProperties(DictMixin):
452    """Directory's properties class.
453
454    :ivar str name:
455        The name of the directory.
456    :ivar ~datetime.datetime last_modified:
457        A datetime object representing the last time the directory was modified.
458    :ivar str etag:
459        The ETag contains a value that you can use to perform operations
460        conditionally.
461    :ivar bool server_encrypted:
462        Whether encryption is enabled.
463    :keyword dict metadata: A dict with name_value pairs to associate with the
464        directory as metadata.
465    :ivar change_time: Change time for the file.
466    :vartype change_time: str or ~datetime.datetime
467    :ivar creation_time: Creation time for the file.
468    :vartype creation_time: str or ~datetime.datetime
469    :ivar last_write_time: Last write time for the file.
470    :vartype last_write_time: str or ~datetime.datetime
471    :ivar file_attributes:
472        The file system attributes for files and directories.
473    :vartype file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes`
474    :ivar permission_key: Key of the permission to be set for the
475        directory/file.
476    :vartype permission_key: str
477    :ivar file_id: Required. FileId uniquely identifies the file or
478     directory.
479    :vartype file_id: str
480    :ivar parent_id: ParentId uniquely identifies the parent directory of the
481     object.
482    :vartype parent_id: str
483    """
484
485    def __init__(self, **kwargs):
486        self.name = None
487        self.last_modified = kwargs.get('Last-Modified')
488        self.etag = kwargs.get('ETag')
489        self.server_encrypted = kwargs.get('x-ms-server-encrypted')
490        self.metadata = kwargs.get('metadata')
491        self.change_time = _parse_datetime_from_str(kwargs.get('x-ms-file-change-time'))
492        self.creation_time = _parse_datetime_from_str(kwargs.get('x-ms-file-creation-time'))
493        self.last_write_time = _parse_datetime_from_str(kwargs.get('x-ms-file-last-write-time'))
494        self.file_attributes = kwargs.get('x-ms-file-attributes')
495        self.permission_key = kwargs.get('x-ms-file-permission-key')
496        self.file_id = kwargs.get('x-ms-file-id')
497        self.parent_id = kwargs.get('x-ms-file-parent-id')
498
499    @classmethod
500    def _from_generated(cls, generated):
501        props = cls()
502        props.name = generated.name
503        props.last_modified = generated.properties.last_modified
504        props.etag = generated.properties.etag
505        props.server_encrypted = generated.properties.server_encrypted
506        props.metadata = generated.metadata
507        return props
508
509
510class DirectoryPropertiesPaged(PageIterator):
511    """An iterable for the contents of a directory.
512
513    This iterable will yield dicts for the contents of the directory. The dicts
514    will have the keys 'name' (str) and 'is_directory' (bool).
515    Items that are files (is_directory=False) will have an additional 'content_length' key.
516
517    :ivar str service_endpoint: The service URL.
518    :ivar str prefix: A file name prefix being used to filter the list.
519    :ivar str marker: The continuation token of the current page of results.
520    :ivar int results_per_page: The maximum number of results retrieved per API call.
521    :ivar str continuation_token: The continuation token to retrieve the next page of results.
522    :ivar str location_mode: The location mode being used to list results. The available
523        options include "primary" and "secondary".
524    :ivar current_page: The current page of listed results.
525    :vartype current_page: list(dict(str, Any))
526
527    :param callable command: Function to retrieve the next page of items.
528    :param str prefix: Filters the results to return only directories whose names
529        begin with the specified prefix.
530    :param int results_per_page: The maximum number of share names to retrieve per
531        call.
532    :param str continuation_token: An opaque continuation token.
533    """
534    def __init__(self, command, prefix=None, results_per_page=None, continuation_token=None):
535        super(DirectoryPropertiesPaged, self).__init__(
536            get_next=self._get_next_cb,
537            extract_data=self._extract_data_cb,
538            continuation_token=continuation_token or ""
539        )
540        self._command = command
541        self.service_endpoint = None
542        self.prefix = prefix
543        self.marker = None
544        self.results_per_page = results_per_page
545        self.location_mode = None
546        self.current_page = []
547
548    def _get_next_cb(self, continuation_token):
549        try:
550            return self._command(
551                marker=continuation_token or None,
552                prefix=self.prefix,
553                maxresults=self.results_per_page,
554                cls=return_context_and_deserialized,
555                use_location=self.location_mode)
556        except StorageErrorException as error:
557            process_storage_error(error)
558
559    def _extract_data_cb(self, get_next_return):
560        self.location_mode, self._response = get_next_return
561        self.service_endpoint = self._response.service_endpoint
562        self.prefix = self._response.prefix
563        self.marker = self._response.marker
564        self.results_per_page = self._response.max_results
565        self.current_page = [_wrap_item(i) for i in self._response.segment.directory_items]
566        self.current_page.extend([_wrap_item(i) for i in self._response.segment.file_items])
567        return self._response.next_marker or None, self.current_page
568
569
570class FileProperties(DictMixin):
571    """File's properties class.
572
573    :ivar str name:
574        The name of the file.
575    :ivar str path:
576        The path of the file.
577    :ivar str share:
578        The name of share.
579    :ivar str snapshot:
580        File snapshot.
581    :ivar int content_length:
582        Size of file in bytes.
583    :ivar dict metadata: A dict with name_value pairs to associate with the
584        file as metadata.
585    :ivar str file_type:
586        Type of the file.
587    :ivar ~datetime.datetime last_modified:
588        A datetime object representing the last time the file was modified.
589    :ivar str etag:
590        The ETag contains a value that you can use to perform operations
591        conditionally.
592    :ivar int size:
593        Size of file in bytes.
594    :ivar str content_range:
595        The range of bytes.
596    :ivar bool server_encrypted:
597        Whether encryption is enabled.
598    :ivar copy:
599        The copy properties.
600    :vartype copy: ~azure.storage.fileshare.CopyProperties
601    :ivar content_settings:
602        The content settings for the file.
603    :vartype content_settings: ~azure.storage.fileshare.ContentSettings
604    """
605
606    def __init__(self, **kwargs):
607        self.name = kwargs.get('name')
608        self.path = None
609        self.share = None
610        self.snapshot = None
611        self.content_length = kwargs.get('Content-Length')
612        self.metadata = kwargs.get('metadata')
613        self.file_type = kwargs.get('x-ms-type')
614        self.last_modified = kwargs.get('Last-Modified')
615        self.etag = kwargs.get('ETag')
616        self.size = kwargs.get('Content-Length')
617        self.content_range = kwargs.get('Content-Range')
618        self.server_encrypted = kwargs.get('x-ms-server-encrypted')
619        self.copy = CopyProperties(**kwargs)
620        self.content_settings = ContentSettings(**kwargs)
621        self.lease = LeaseProperties(**kwargs)
622        self.change_time = _parse_datetime_from_str(kwargs.get('x-ms-file-change-time'))
623        self.creation_time = _parse_datetime_from_str(kwargs.get('x-ms-file-creation-time'))
624        self.last_write_time = _parse_datetime_from_str(kwargs.get('x-ms-file-last-write-time'))
625        self.file_attributes = kwargs.get('x-ms-file-attributes')
626        self.permission_key = kwargs.get('x-ms-file-permission-key')
627        self.file_id = kwargs.get('x-ms-file-id')
628        self.parent_id = kwargs.get('x-ms-file-parent-id')
629
630    @classmethod
631    def _from_generated(cls, generated):
632        props = cls()
633        props.name = generated.name
634        props.content_length = generated.properties.content_length
635        props.metadata = generated.properties.metadata
636        props.lease = LeaseProperties._from_generated(generated)  # pylint: disable=protected-access
637        return props
638
639
640class CopyProperties(DictMixin):
641    """File Copy Properties.
642
643    :ivar str id:
644        String identifier for the last attempted Copy File operation where this file
645        was the destination file. This header does not appear if this file has never
646        been the destination in a Copy File operation, or if this file has been
647        modified after a concluded Copy File operation.
648    :ivar str source:
649        URL up to 2 KB in length that specifies the source file used in the last attempted
650        Copy File operation where this file was the destination file. This header does not
651        appear if this file has never been the destination in a Copy File operation, or if
652        this file has been modified after a concluded Copy File operation.
653    :ivar str status:
654        State of the copy operation identified by Copy ID, with these values:
655            success:
656                Copy completed successfully.
657            pending:
658                Copy is in progress. Check copy_status_description if intermittent,
659                non-fatal errors impede copy progress but don't cause failure.
660            aborted:
661                Copy was ended by Abort Copy File.
662            failed:
663                Copy failed. See copy_status_description for failure details.
664    :ivar str progress:
665        Contains the number of bytes copied and the total bytes in the source in the last
666        attempted Copy File operation where this file was the destination file. Can show
667        between 0 and Content-Length bytes copied.
668    :ivar datetime completion_time:
669        Conclusion time of the last attempted Copy File operation where this file was the
670        destination file. This value can specify the time of a completed, aborted, or
671        failed copy attempt.
672    :ivar str status_description:
673        Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal
674        or non-fatal copy operation failure.
675    :ivar bool incremental_copy:
676        Copies the snapshot of the source file to a destination file.
677        The snapshot is copied such that only the differential changes between
678        the previously copied snapshot are transferred to the destination
679    :ivar datetime destination_snapshot:
680        Included if the file is incremental copy or incremental copy snapshot,
681        if x-ms-copy-status is success. Snapshot time of the last successful
682        incremental copy snapshot for this file.
683    """
684
685    def __init__(self, **kwargs):
686        self.id = kwargs.get('x-ms-copy-id')
687        self.source = kwargs.get('x-ms-copy-source')
688        self.status = get_enum_value(kwargs.get('x-ms-copy-status'))
689        self.progress = kwargs.get('x-ms-copy-progress')
690        self.completion_time = kwargs.get('x-ms-copy-completion_time')
691        self.status_description = kwargs.get('x-ms-copy-status-description')
692        self.incremental_copy = kwargs.get('x-ms-incremental-copy')
693        self.destination_snapshot = kwargs.get('x-ms-copy-destination-snapshot')
694
695    @classmethod
696    def _from_generated(cls, generated):
697        copy = cls()
698        copy.id = generated.properties.copy_id or None
699        copy.status = get_enum_value(generated.properties.copy_status) or None
700        copy.source = generated.properties.copy_source or None
701        copy.progress = generated.properties.copy_progress or None
702        copy.completion_time = generated.properties.copy_completion_time or None
703        copy.status_description = generated.properties.copy_status_description or None
704        copy.incremental_copy = generated.properties.incremental_copy or None
705        copy.destination_snapshot = generated.properties.destination_snapshot or None
706        return copy
707
708
709class FileSasPermissions(object):
710    """FileSasPermissions class to be used with
711    generating shared access signature operations.
712
713    :param bool read:
714        Read the content, properties, metadata. Use the file as the source of a copy
715        operation.
716    :param bool create:
717        Create a new file or copy a file to a new file.
718    :param bool write:
719        Create or write content, properties, metadata. Resize the file. Use the file
720        as the destination of a copy operation within the same account.
721    :param bool delete:
722        Delete the file.
723    """
724    def __init__(self, read=False, create=False, write=False, delete=False):
725        self.read = read
726        self.create = create
727        self.write = write
728        self.delete = delete
729        self._str = (('r' if self.read else '') +
730                     ('c' if self.create else '') +
731                     ('w' if self.write else '') +
732                     ('d' if self.delete else ''))
733
734    def __str__(self):
735        return self._str
736
737    @classmethod
738    def from_string(cls, permission):
739        """Create a FileSasPermissions from a string.
740
741        To specify read, create, write, or delete permissions you need only to
742        include the first letter of the word in the string. E.g. For read and
743        create permissions, you would provide a string "rc".
744
745        :param str permission: The string which dictates the read, create,
746            write, or delete permissions
747        :return: A FileSasPermissions object
748        :rtype: ~azure.storage.fileshare.FileSasPermissions
749        """
750        p_read = 'r' in permission
751        p_create = 'c' in permission
752        p_write = 'w' in permission
753        p_delete = 'd' in permission
754
755        parsed = cls(p_read, p_create, p_write, p_delete)
756        parsed._str = permission # pylint: disable = protected-access
757        return parsed
758
759
760class ShareSasPermissions(object):
761    """ShareSasPermissions class to be used to be used with
762    generating shared access signature and access policy operations.
763
764    :param bool read:
765        Read the content, properties or metadata of any file in the share. Use any
766        file in the share as the source of a copy operation.
767    :param bool write:
768        For any file in the share, create or write content, properties or metadata.
769        Resize the file. Use the file as the destination of a copy operation within
770        the same account.
771        Note: You cannot grant permissions to read or write share properties or
772        metadata with a service SAS. Use an account SAS instead.
773    :param bool delete:
774        Delete any file in the share.
775        Note: You cannot grant permissions to delete a share with a service SAS. Use
776        an account SAS instead.
777    :param bool list:
778        List files and directories in the share.
779    """
780    def __init__(self, read=False, write=False, delete=False, list=False):  # pylint: disable=redefined-builtin
781        self.read = read
782        self.write = write
783        self.delete = delete
784        self.list = list
785        self._str = (('r' if self.read else '') +
786                     ('w' if self.write else '') +
787                     ('d' if self.delete else '') +
788                     ('l' if self.list else ''))
789
790
791    def __str__(self):
792        return self._str
793
794    @classmethod
795    def from_string(cls, permission):
796        """Create a ShareSasPermissions from a string.
797
798        To specify read, write, delete, or list permissions you need only to
799        include the first letter of the word in the string. E.g. For read and
800        write permissions, you would provide a string "rw".
801
802        :param str permission: The string which dictates the read, write,
803            delete, or list permissions
804        :return: A ShareSasPermissions object
805        :rtype: ~azure.storage.fileshare.ShareSasPermissions
806        """
807        p_read = 'r' in permission
808        p_write = 'w' in permission
809        p_delete = 'd' in permission
810        p_list = 'l' in permission
811
812        parsed = cls(p_read, p_write, p_delete, p_list)
813        parsed._str = permission # pylint: disable = protected-access
814        return parsed
815
816class NTFSAttributes(object):
817    """
818    Valid set of attributes to set for file or directory.
819    To set attribute for directory, 'Directory' should always be enabled except setting 'None' for directory.
820
821    :ivar bool read_only:
822        Enable/disable 'ReadOnly' attribute for DIRECTORY or FILE
823    :ivar bool hidden:
824        Enable/disable 'Hidden' attribute for DIRECTORY or FILE
825    :ivar bool system:
826        Enable/disable 'System' attribute for DIRECTORY or FILE
827    :ivar bool none:
828        Enable/disable 'None' attribute for DIRECTORY or FILE to clear all attributes of FILE/DIRECTORY
829    :ivar bool directory:
830        Enable/disable 'Directory' attribute for DIRECTORY
831    :ivar bool archive:
832        Enable/disable 'Archive' attribute for DIRECTORY or FILE
833    :ivar bool temporary:
834        Enable/disable 'Temporary' attribute for FILE
835    :ivar bool offline:
836        Enable/disable 'Offline' attribute for DIRECTORY or FILE
837    :ivar bool not_content_indexed:
838        Enable/disable 'NotContentIndexed' attribute for DIRECTORY or FILE
839    :ivar bool no_scrub_data:
840        Enable/disable 'NoScrubData' attribute for DIRECTORY or FILE
841    """
842    def __init__(self, read_only=False, hidden=False, system=False, none=False, directory=False, archive=False,
843                 temporary=False, offline=False, not_content_indexed=False, no_scrub_data=False):
844
845        self.read_only = read_only
846        self.hidden = hidden
847        self.system = system
848        self.none = none
849        self.directory = directory
850        self.archive = archive
851        self.temporary = temporary
852        self.offline = offline
853        self.not_content_indexed = not_content_indexed
854        self.no_scrub_data = no_scrub_data
855        self._str = (('ReadOnly|' if self.read_only else '') +
856                               ('Hidden|' if self.hidden else '') +
857                               ('System|' if self.system else '') +
858                               ('None|' if self.none else '') +
859                               ('Directory|' if self.directory else '') +
860                               ('Archive|' if self.archive else '') +
861                               ('Temporary|' if self.temporary else '') +
862                               ('Offline|' if self.offline else '') +
863                               ('NotContentIndexed|' if self.not_content_indexed else '') +
864                               ('NoScrubData|' if self.no_scrub_data else ''))
865
866    def __str__(self):
867        concatenated_params = self._str
868        return concatenated_params.strip('|')
869
870    @classmethod
871    def from_string(cls, string):
872        """Create a NTFSAttributes from a string.
873
874        To specify permissions you can pass in a string with the
875        desired permissions, e.g. "ReadOnly|Hidden|System"
876
877        :param str string: The string which dictates the permissions.
878        :return: A NTFSAttributes object
879        :rtype: ~azure.storage.fileshare.NTFSAttributes
880        """
881        read_only = "ReadOnly" in string
882        hidden = "Hidden" in string
883        system = "System" in string
884        none = "None" in string
885        directory = "Directory" in string
886        archive = "Archive" in string
887        temporary = "Temporary" in string
888        offline = "Offline" in string
889        not_content_indexed = "NotContentIndexed" in string
890        no_scrub_data = "NoScrubData" in string
891
892        parsed = cls(read_only, hidden, system, none, directory, archive, temporary, offline, not_content_indexed,
893                     no_scrub_data)
894        parsed._str = string  # pylint: disable = protected-access
895        return parsed
896
897
898def service_properties_deserialize(generated):
899    """Deserialize a ServiceProperties objects into a dict.
900    """
901    return {
902        'hour_metrics': Metrics._from_generated(generated.hour_metrics),  # pylint: disable=protected-access
903        'minute_metrics': Metrics._from_generated(generated.minute_metrics),  # pylint: disable=protected-access
904        'cors': [CorsRule._from_generated(cors) for cors in generated.cors],  # pylint: disable=protected-access
905    }
906