<commit_before>#!/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 os
import io
import json
import shutil
import zipfile

from .. import base

from girder.constants import AccessType, ROOT_DIR

def setUpModule():
    base.startServer()

def tearDownModule():
    base.stopServer()

class ItemTestCase(base.TestCase):

    def setUp(self):
        base.TestCase.setUp(self)

        # Create a set of users so we can have some folders.
        self.users = [self.model('user').createUser(
            'usr%s' % num, 'passwd', 'tst', 'usr', 'u%s@u.com' % num)
            for num in [0, 1]]

        folders = self.model('folder').childFolders(
            self.users[0], 'user', user=self.users[0])
        (self.publicFolder, self.privateFolder) = folders

        self.assetstore = self.model('assetstore').getCurrent()
        root = self.assetstore['root']

        # Clean out the test assetstore on disk
        shutil.rmtree(root)

        # First clean out the temp directory
        tmpdir = os.path.join(root, 'temp')
        if os.path.isdir(tmpdir):
            for tempname in os.listdir(tmpdir):
                os.remove(os.path.join(tmpdir, tempname))

    def _createItem(self, parentId, name, description, user):
        params = {
            'name': name,
            'description': description,
            'folderId': parentId
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=user)
        self.assertStatusOk(resp)
        return resp.json

    def _testUploadFileToItem(self, item, name, user, contents):
        """
        Uploads a non-empty file to the server.
        """
        # Initialize the upload
        resp = self.request(
            path='/file', method='POST', user=user, params={
                'parentType': 'item',
                'parentId': item['_id'],
                'name': name,
                'size': len(contents)
            })
        self.assertStatusOk(resp)

        uploadId = resp.json['_id']

        # Send the first chunk
        fields = [('offset', 0), ('uploadId', uploadId)]
        files = [('chunk', name, contents)]
        resp = self.multipartRequest(
            path='/file/chunk', user=user, fields=fields, files=files)
        self.assertStatusOk(resp)

    def _testDownloadSingleFileItem(self, item, user, contents):
        """
        Downloads a single-file item from the server
        :param item: The item to download.
        :type item: dict
        :param contents: The expected contents.
        :type contents: str
        """
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False)
        self.assertStatusOk(resp)

        self.assertEqual(contents, resp.collapse_body())

        # Test downloading with an offset
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False,
                            params={'offset': 1})
        self.assertStatusOk(resp)

        self.assertEqual(contents[1:], resp.collapse_body())

    def _testDownloadMultiFileItem(self, item, user, contents):
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False)
        self.assertStatusOk(resp)
        zipFile = zipfile.ZipFile(io.BytesIO(resp.collapse_body()), 'r')
        filesInItem = zipFile.namelist()
        self.assertEqual(zipFile.read(filesInItem[0]), contents[0])
        self.assertEqual(zipFile.read(filesInItem[1]), contents[1])

    def testItemDownloadAndChildren(self):
        curItem = self._createItem(self.publicFolder['_id'],
                                   'test_for_download', 'fake description',
                                   self.users[0])
        self._testUploadFileToItem(curItem, 'file_1', self.users[0], 'foobar')

        self._testDownloadSingleFileItem(curItem, self.users[0], 'foobar')

        self._testUploadFileToItem(curItem, 'file_2', self.users[0], 'foobz')

        resp = self.request(path='/item/{}/files'.format(curItem['_id']),
                            method='GET', user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json[0]['name'], 'file_1')
        self.assertEqual(resp.json[1]['name'], 'file_2')
        self.assertEqual(resp.json[0]['size'], 6)
        self.assertEqual(resp.json[1]['size'], 5)

        self._testDownloadMultiFileItem(curItem, self.users[0],
                                        ('foobar', 'foobz'))

    def testItemCrud(self):
        """
        Test Create, Read, Update, and Delete of items.
        """
        self.ensureRequiredParams(
            path='/item', method='POST', required=('name', 'folderId'))

        # Attempt to create an item without write permission, should fail
        params = {
            'name': ' ',
            'description': ' a description ',
            'folderId': self.publicFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # Shouldn't be allowed to have an empty name
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertValidationError(resp, 'name')

        # Actually create the item in user 0's private folder
        params['name'] = ' my item name'
        params['folderId'] = self.privateFolder['_id']
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)

        item = resp.json
        self.assertEqual(item['name'], params['name'].strip())
        self.assertEqual(item['description'], params['description'].strip())

        # User 1 should not be able to see the item via find by folderId
        params = {
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='GET', user=self.users[1],
                            params=params)
        self.assertStatus(resp, 403)

        # Or by just requesting the item itself by ID
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # User 0 should be able to see the item
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['_id'], item['_id'])

        # Also from the children call
        resp = self.request(path='/item', method='GET', user=self.users[0],
                            params=params)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json[0]['_id'], item['_id'])

        # Test update of the item
        params = {
            'name': 'changed name',
            'description': 'new description'
        }
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            params=params, user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['name'], params['name'])
        self.assertEqual(resp.json['description'], params['description'])

        # Test moving an item to the public folder
        item = self.model('item').load(item['_id'], force=True)
        self.assertFalse(self.model('item').hasAccess(item))
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            user=self.users[0], params={
                                'folderId': self.publicFolder['_id']
                                })
        self.assertStatusOk(resp)
        item = self.model('item').load(resp.json['_id'], force=True)
        self.assertTrue(self.model('item').hasAccess(item))

        # Move should fail if we don't have write permission on the dest folder
        self.publicFolder = self.model('folder').setUserAccess(
            self.publicFolder, self.users[1], AccessType.WRITE, save=True)
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            user=self.users[1], params={
                                'folderId': self.privateFolder['_id']
                                })
        self.assertStatus(resp, 403)
        self.assertEqual(resp.json['message'],
                         'Write access denied for folder.')

        # Try to update/PUT without an id
        resp = self.request(path='/item/', method='PUT',
                            params=params, user=self.users[0])
        self.assertStatus(resp, 400)

        # Try a bad endpoint (should 400)
        resp = self.request(path='/item/{}/blurgh'.format(item['_id']),
                            method='GET',
                            user=self.users[1])
        self.assertStatus(resp, 400)

        # Try delete with no ID (should 400)
        resp = self.request(path='/item/', method='DELETE', user=self.users[1])
        self.assertStatus(resp, 400)

        # User 1 should not be able to delete the item
        resp = self.request(path='/item/%s' % str(item['_id']), method='DELETE',
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # User 0 should be able to delete the item
        resp = self.request(path='/item/%s' % str(item['_id']), method='DELETE',
                            user=self.users[0])
        self.assertStatusOk(resp)

        # Verify that the item is deleted
        item = self.model('item').load(item['_id'])
        self.assertEqual(item, None)

    def testItemMetadataCrud(self):
        """
        Test CRUD of metadata.
        """

        # Create an item
        params = {
            'name': 'item with metadata',
            'description': ' a description ',
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)
        item = resp.json

        # Add some metadata
        metadata = {
            'foo': 'bar',
            'test': 2
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')

        item = resp.json
        self.assertEqual(item['meta']['foo'], metadata['foo'])
        self.assertEqual(item['meta']['test'], metadata['test'])

        # Edit and remove metadata
        metadata['test'] = None
        metadata['foo'] = 'baz'
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')

        item = resp.json
        self.assertEqual(item['meta']['foo'], metadata['foo'])
        self.assertNotHasKeys(item['meta'], ['test'])

        # Make sure metadata cannot be added if there is a period in the key
        # name
        metadata = {
            'foo.bar': 'notallowed'
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'],
                         'The key name foo.bar must not contain a period' +
                         ' or begin with a dollar sign.')

        # Make sure metadata cannot be added if the key begins with a
        # dollar sign
        metadata = {
            '$foobar': 'alsonotallowed'
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'],
                         'The key name $foobar must not contain a period' +
                         ' or begin with a dollar sign.')

    def testItemFiltering(self):
        """
        Test filtering private metadata from items.
        """

        # Create an item
        params = {
            'name': 'item with metadata',
            'description': ' a description ',
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)

        # get the item object from the database
        item = self.model('item').load(resp.json['_id'], force=True)

        # set a private property
        item['private'] = 'very secret metadata'
        self.model('item').save(item)

        # get the item from the rest api
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[0])
        self.assertStatusOk(resp)

        # assert that the private data is not included
        self.assertNotHasKeys(resp.json, ['private'])

    def testPathToRoot(self):
        firstChildName = 'firstChild'
        firstChildDesc = 'firstDesc'
        secondChildName = 'secondChild'
        secondChildDesc = 'secondDesc'

        firstChild = self.model('folder').createFolder(self.publicFolder,
                                                       firstChildName,
                                                       firstChildDesc,
                                                       creator=self.users[0])
        secondChild = self.model('folder').createFolder(firstChild,
                                                        secondChildName,
                                                        secondChildDesc,
                                                        creator=self.users[0])
        baseItem = self.model('item').createItem('blah', self.users[0],
                                                 secondChild, 'foo')

        resp = self.request(path='/item/{}/rootpath'.format(baseItem['_id']),
                            method='GET')
        self.assertStatusOk(resp)
        pathToRoot = resp.json

        self.assertEqual(pathToRoot[0]['type'], 'user')
        self.assertEqual(pathToRoot[0]['object']['login'],
                         self.users[0]['login'])
        self.assertEqual(pathToRoot[1]['type'], 'folder')
        self.assertEqual(pathToRoot[1]['object']['name'],
                         self.publicFolder['name'])
        self.assertEqual(pathToRoot[2]['type'], 'folder')
        self.assertEqual(pathToRoot[2]['object']['name'], firstChild['name'])
        self.assertEqual(pathToRoot[3]['type'], 'folder')
        self.assertEqual(pathToRoot[3]['object']['name'], secondChild['name'])

    def testLazyFieldComputation(self):
        """
        Demonstrate that an item that is saved in the database without
        derived fields (like lowerName or baseParentId) get those values
        computed at load() time.
        """
        item = self.model('item').createItem(
            'My Item Name', creator=self.users[0], folder=self.publicFolder)

        self.assertEqual(item['lowerName'], 'my item name')
        self.assertEqual(item['baseParentId'], self.users[0]['_id'])

        # Force the item to be saved without lowerName and baseParentType fields
        del item['lowerName']
        del item['baseParentType']
        self.model('item').save(item, validate=False)

        item = self.model('item').find({'_id': item['_id']}).next()
        self.assertNotHasKeys(item, ('lowerName', 'baseParentType'))

        # Now ensure that calling load() actually populates those fields and
        # saves the results persistently
        self.model('item').load(item['_id'], force=True)
        item = self.model('item').find({'_id': item['_id']}).next()
        self.assertHasKeys(item, ('lowerName', 'baseParentType'))
        self.assertEqual(item['lowerName'], 'my item name')
        self.assertEqual(item['baseParentType'], 'user')
        self.assertEqual(item['baseParentId'], self.users[0]['_id'])
<commit_msg>Testing read-level delete fail, write-level delete success<commit_after>#!/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 os
import io
import json
import shutil
import zipfile

from .. import base

from girder.constants import AccessType, ROOT_DIR

def setUpModule():
    base.startServer()

def tearDownModule():
    base.stopServer()

class ItemTestCase(base.TestCase):

    def setUp(self):
        base.TestCase.setUp(self)

        # Create a set of users so we can have some folders.
        self.users = [self.model('user').createUser(
            'usr%s' % num, 'passwd', 'tst', 'usr', 'u%s@u.com' % num)
            for num in [0, 1]]

        folders = self.model('folder').childFolders(
            self.users[0], 'user', user=self.users[0])
        (self.publicFolder, self.privateFolder) = folders

        self.assetstore = self.model('assetstore').getCurrent()
        root = self.assetstore['root']

        # Clean out the test assetstore on disk
        shutil.rmtree(root)

        # First clean out the temp directory
        tmpdir = os.path.join(root, 'temp')
        if os.path.isdir(tmpdir):
            for tempname in os.listdir(tmpdir):
                os.remove(os.path.join(tmpdir, tempname))

    def _createItem(self, parentId, name, description, user):
        params = {
            'name': name,
            'description': description,
            'folderId': parentId
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=user)
        self.assertStatusOk(resp)
        return resp.json

    def _testUploadFileToItem(self, item, name, user, contents):
        """
        Uploads a non-empty file to the server.
        """
        # Initialize the upload
        resp = self.request(
            path='/file', method='POST', user=user, params={
                'parentType': 'item',
                'parentId': item['_id'],
                'name': name,
                'size': len(contents)
            })
        self.assertStatusOk(resp)

        uploadId = resp.json['_id']

        # Send the first chunk
        fields = [('offset', 0), ('uploadId', uploadId)]
        files = [('chunk', name, contents)]
        resp = self.multipartRequest(
            path='/file/chunk', user=user, fields=fields, files=files)
        self.assertStatusOk(resp)

    def _testDownloadSingleFileItem(self, item, user, contents):
        """
        Downloads a single-file item from the server
        :param item: The item to download.
        :type item: dict
        :param contents: The expected contents.
        :type contents: str
        """
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False)
        self.assertStatusOk(resp)

        self.assertEqual(contents, resp.collapse_body())

        # Test downloading with an offset
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False,
                            params={'offset': 1})
        self.assertStatusOk(resp)

        self.assertEqual(contents[1:], resp.collapse_body())

    def _testDownloadMultiFileItem(self, item, user, contents):
        resp = self.request(path='/item/{}/download'.format(item['_id']),
                            method='GET', user=user, isJson=False)
        self.assertStatusOk(resp)
        zipFile = zipfile.ZipFile(io.BytesIO(resp.collapse_body()), 'r')
        filesInItem = zipFile.namelist()
        self.assertEqual(zipFile.read(filesInItem[0]), contents[0])
        self.assertEqual(zipFile.read(filesInItem[1]), contents[1])

    def testItemDownloadAndChildren(self):
        curItem = self._createItem(self.publicFolder['_id'],
                                   'test_for_download', 'fake description',
                                   self.users[0])
        self._testUploadFileToItem(curItem, 'file_1', self.users[0], 'foobar')

        self._testDownloadSingleFileItem(curItem, self.users[0], 'foobar')

        self._testUploadFileToItem(curItem, 'file_2', self.users[0], 'foobz')

        resp = self.request(path='/item/{}/files'.format(curItem['_id']),
                            method='GET', user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json[0]['name'], 'file_1')
        self.assertEqual(resp.json[1]['name'], 'file_2')
        self.assertEqual(resp.json[0]['size'], 6)
        self.assertEqual(resp.json[1]['size'], 5)

        self._testDownloadMultiFileItem(curItem, self.users[0],
                                        ('foobar', 'foobz'))

    def testItemCrud(self):
        """
        Test Create, Read, Update, and Delete of items.
        """
        self.ensureRequiredParams(
            path='/item', method='POST', required=('name', 'folderId'))

        # Attempt to create an item without write permission, should fail
        params = {
            'name': ' ',
            'description': ' a description ',
            'folderId': self.publicFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # Shouldn't be allowed to have an empty name
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertValidationError(resp, 'name')

        # Actually create the item in user 0's private folder
        params['name'] = ' my item name'
        params['folderId'] = self.privateFolder['_id']
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)

        item = resp.json
        self.assertEqual(item['name'], params['name'].strip())
        self.assertEqual(item['description'], params['description'].strip())

        # User 1 should not be able to see the item via find by folderId
        params = {
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='GET', user=self.users[1],
                            params=params)
        self.assertStatus(resp, 403)

        # Or by just requesting the item itself by ID
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # User 0 should be able to see the item
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['_id'], item['_id'])

        # Also from the children call
        resp = self.request(path='/item', method='GET', user=self.users[0],
                            params=params)
        self.assertStatusOk(resp)
        self.assertEqual(resp.json[0]['_id'], item['_id'])

        # Test update of the item
        params = {
            'name': 'changed name',
            'description': 'new description'
        }
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            params=params, user=self.users[0])
        self.assertStatusOk(resp)
        self.assertEqual(resp.json['name'], params['name'])
        self.assertEqual(resp.json['description'], params['description'])

        # Test moving an item to the public folder
        item = self.model('item').load(item['_id'], force=True)
        self.assertFalse(self.model('item').hasAccess(item))
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            user=self.users[0], params={
                                'folderId': self.publicFolder['_id']
                                })
        self.assertStatusOk(resp)
        item = self.model('item').load(resp.json['_id'], force=True)
        self.assertTrue(self.model('item').hasAccess(item))

        # Move should fail if we don't have write permission on the dest folder
        self.publicFolder = self.model('folder').setUserAccess(
            self.publicFolder, self.users[1], AccessType.WRITE, save=True)
        resp = self.request(path='/item/{}'.format(item['_id']), method='PUT',
                            user=self.users[1], params={
                                'folderId': self.privateFolder['_id']
                                })
        self.assertStatus(resp, 403)
        self.assertEqual(resp.json['message'],
                         'Write access denied for folder.')

        # Try to update/PUT without an id
        resp = self.request(path='/item/', method='PUT',
                            params=params, user=self.users[0])
        self.assertStatus(resp, 400)

        # Try a bad endpoint (should 400)
        resp = self.request(path='/item/{}/blurgh'.format(item['_id']),
                            method='GET',
                            user=self.users[1])
        self.assertStatus(resp, 400)

        # Try delete with no ID (should 400)
        resp = self.request(path='/item/', method='DELETE', user=self.users[1])
        self.assertStatus(resp, 400)

        # User 1 should not be able to delete the item with read access
        self.publicFolder = self.model('folder').setUserAccess(
            self.publicFolder, self.users[1], AccessType.READ, save=True)
        resp = self.request(path='/item/%s' % str(item['_id']), method='DELETE',
                            user=self.users[1])
        self.assertStatus(resp, 403)

        # User 1 should be able to delete the item with write access
        self.publicFolder = self.model('folder').setUserAccess(
            self.publicFolder, self.users[1], AccessType.WRITE, save=True)
        resp = self.request(path='/item/%s' % str(item['_id']), method='DELETE',
                            user=self.users[1])
        self.assertStatusOk(resp)

        # Verify that the item is deleted
        item = self.model('item').load(item['_id'])
        self.assertEqual(item, None)

    def testItemMetadataCrud(self):
        """
        Test CRUD of metadata.
        """

        # Create an item
        params = {
            'name': 'item with metadata',
            'description': ' a description ',
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)
        item = resp.json

        # Add some metadata
        metadata = {
            'foo': 'bar',
            'test': 2
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')

        item = resp.json
        self.assertEqual(item['meta']['foo'], metadata['foo'])
        self.assertEqual(item['meta']['test'], metadata['test'])

        # Edit and remove metadata
        metadata['test'] = None
        metadata['foo'] = 'baz'
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')

        item = resp.json
        self.assertEqual(item['meta']['foo'], metadata['foo'])
        self.assertNotHasKeys(item['meta'], ['test'])

        # Make sure metadata cannot be added if there is a period in the key
        # name
        metadata = {
            'foo.bar': 'notallowed'
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'],
                         'The key name foo.bar must not contain a period' +
                         ' or begin with a dollar sign.')

        # Make sure metadata cannot be added if the key begins with a
        # dollar sign
        metadata = {
            '$foobar': 'alsonotallowed'
        }
        resp = self.request(path='/item/{}/metadata'.format(item['_id']),
                            method='PUT', user=self.users[0],
                            body=json.dumps(metadata), type='application/json')
        self.assertStatus(resp, 400)
        self.assertEqual(resp.json['message'],
                         'The key name $foobar must not contain a period' +
                         ' or begin with a dollar sign.')

    def testItemFiltering(self):
        """
        Test filtering private metadata from items.
        """

        # Create an item
        params = {
            'name': 'item with metadata',
            'description': ' a description ',
            'folderId': self.privateFolder['_id']
        }
        resp = self.request(path='/item', method='POST', params=params,
                            user=self.users[0])
        self.assertStatusOk(resp)

        # get the item object from the database
        item = self.model('item').load(resp.json['_id'], force=True)

        # set a private property
        item['private'] = 'very secret metadata'
        self.model('item').save(item)

        # get the item from the rest api
        resp = self.request(path='/item/%s' % str(item['_id']), method='GET',
                            user=self.users[0])
        self.assertStatusOk(resp)

        # assert that the private data is not included
        self.assertNotHasKeys(resp.json, ['private'])

    def testPathToRoot(self):
        firstChildName = 'firstChild'
        firstChildDesc = 'firstDesc'
        secondChildName = 'secondChild'
        secondChildDesc = 'secondDesc'

        firstChild = self.model('folder').createFolder(self.publicFolder,
                                                       firstChildName,
                                                       firstChildDesc,
                                                       creator=self.users[0])
        secondChild = self.model('folder').createFolder(firstChild,
                                                        secondChildName,
                                                        secondChildDesc,
                                                        creator=self.users[0])
        baseItem = self.model('item').createItem('blah', self.users[0],
                                                 secondChild, 'foo')

        resp = self.request(path='/item/{}/rootpath'.format(baseItem['_id']),
                            method='GET')
        self.assertStatusOk(resp)
        pathToRoot = resp.json

        self.assertEqual(pathToRoot[0]['type'], 'user')
        self.assertEqual(pathToRoot[0]['object']['login'],
                         self.users[0]['login'])
        self.assertEqual(pathToRoot[1]['type'], 'folder')
        self.assertEqual(pathToRoot[1]['object']['name'],
                         self.publicFolder['name'])
        self.assertEqual(pathToRoot[2]['type'], 'folder')
        self.assertEqual(pathToRoot[2]['object']['name'], firstChild['name'])
        self.assertEqual(pathToRoot[3]['type'], 'folder')
        self.assertEqual(pathToRoot[3]['object']['name'], secondChild['name'])

    def testLazyFieldComputation(self):
        """
        Demonstrate that an item that is saved in the database without
        derived fields (like lowerName or baseParentId) get those values
        computed at load() time.
        """
        item = self.model('item').createItem(
            'My Item Name', creator=self.users[0], folder=self.publicFolder)

        self.assertEqual(item['lowerName'], 'my item name')
        self.assertEqual(item['baseParentId'], self.users[0]['_id'])

        # Force the item to be saved without lowerName and baseParentType fields
        del item['lowerName']
        del item['baseParentType']
        self.model('item').save(item, validate=False)

        item = self.model('item').find({'_id': item['_id']}).next()
        self.assertNotHasKeys(item, ('lowerName', 'baseParentType'))

        # Now ensure that calling load() actually populates those fields and
        # saves the results persistently
        self.model('item').load(item['_id'], force=True)
        item = self.model('item').find({'_id': item['_id']}).next()
        self.assertHasKeys(item, ('lowerName', 'baseParentType'))
        self.assertEqual(item['lowerName'], 'my item name')
        self.assertEqual(item['baseParentType'], 'user')
        self.assertEqual(item['baseParentId'], self.users[0]['_id'])
<|endoftext|>


<commit_before>import sys
import sqlite3
import urllib.parse

from datetime import datetime

from lxml.html import parse

INDEX_INDEX = 'http://tvtropes.org/pmwiki/index_report.php'
WIKI_PAGE = 'http://tvtropes.org/pmwiki/pmwiki.php/'

def list_pages(namespace_url=None):
    list_url = namespace_url or INDEX_INDEX
    print('Crawling {}'.format(list_url))
    tree = parse(list_url)

    for a in tree.xpath('//a[@class="twikilink"]'):
        name = a.text.strip()
        url = a.attrib['href']
        if namespace_url:
            yield (name,), url
        else:
            yield ('Main', name), url

    if not namespace_url:
        namespaces = tree.xpath(
            '//a[starts-with(@href, "index_report.php?groupname=")]'
        )

        for a in namespaces:
            namespace = a.text.strip()
            url = urllib.parse.urljoin(
                INDEX_INDEX, a.attrib['href']
            )
            for key, value in list_pages(url):
                assert len(key) == 1
                yield (namespace,) + key, value

def save_links(links, cur):
    cur.execute('''
        CREATE TABLE IF NOT EXISTS indexindex
        (
        namespace text, name text, url text, last_crawled timestamp,
        constraint pk_indexindex primary key(namespace, name)
        )
    ''')
    for name, url in links:
        try:
            cur.execute('INSERT INTO indexindex VALUES (?, ?, ?, NULL)',
                        (name[0], name[1], url))
        except sqlite3.IntegrityError:
            cur.execute('UPDATE indexindex SET url = ? '
                        'WHERE namespace = ? and name = ?',
                        (url, name[0], name[1]))
    print('Total {}'.format(cur.execute('SELECT count(*) FROM indexindex')
                            .fetchone()[0]))

def links_to_crawl(crawl_queue):
    while crawl_queue:
        link = crawl_queue.pop(0)
        if len(link) == 3:
            yield link + (None,)
        else:
            yield link

def crawl_links(crawl_queue, conn):
    c = conn.cursor()
    c.execute('''
        CREATE TABLE IF NOT EXISTS relations
        (
        origin_namespace text, origin text,
        destination_namespace text, destination text,
        constraint pk_relations primary key(origin_namespace, origin,
        destination_namespace, destination)
        )
        ''')
    for namespace, name, url, referer in links_to_crawl(crawl_queue):
        current_time = datetime.now()
        tree = parse(url)
        if namespace is None:
            namespace = tree.xpath('//div[@class="pagetitle"]')[0] \
                .text.strip()[:-1]
            if namespace == '':
                namespace = 'Main'
        if c.execute('SELECT count(*) FROM indexindex '
                     'WHERE namespace = ? and name = ?',
                     (namespace, name)).fetchone()[0] != 0:
            last_crawled = c.execute('SELECT last_crawled FROM indexindex '
                                     'WHERE namespace = ? and name = ?',
                                     (namespace, name)).fetchone()
            if last_crawled is not None:
                if last_crawled[0] is not None:
                    if (current_time - last_crawled[0]).days < 1:
                        continue
        else:
            try:
                c.execute('INSERT INTO indexindex VALUES (?, ?, ?, ?)',
                          (namespace, name, url, None))
            except sqlite3.IntegrityError:
                pass
        conn.commit()
        print("Fetching: {}/{} @ {}"
              .format(namespace, name, url))
        for a in tree.xpath('//a[@class="twikilink"]'):
            try:
                destination_name = a.text.strip()
                destination_url = urllib.parse.urljoin(
                    WIKI_PAGE, a.attrib['href']
                )
                next_crawl = (None, destination_name, destination_url,
                              (namespace, name))
                if next_crawl not in crawl_queue:
                    crawl_queue.append(next_crawl)
            except AttributeError:
                pass
        if referer is not None:
            try:
                c.execute('INSERT INTO relations VALUES (?, ?, ?, ?)',
                          (referer[0], referer[1], namespace, name))
            except sqlite3.IntegrityError:
                pass
        print('Crawling {}/{} @ {} completed at {}'
              .format(namespace, name, url, current_time))
        c.execute('''
            UPDATE indexindex SET last_crawled = ?
            WHERE namespace = ? and name = ?
                ''', (current_time, namespace, name))

general_help_string = '''
Usage: python crawler.py <command> <arguments>

commands:

    init:
        Usage: python crawler.py init <db-file>

        Crawls indexindex of TVTropes.
        If an entry already exists, it is updated to new url.
        If the process is inturruped in the middle, nothing will be saved.

    relation:
        Usage: python crawler.py relation <db-file>

        Crawls each pages and saves it to a table, using items in
        indexindex table as seeds. New pages are saved to indexindex table,
        and relationship of pages are saved to relations table.
        If indexindex table is not found, an error will be raised.

If a db file is not already present with each commands, one will be
automatically created.
'''.strip()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        if sys.argv[1] == 'init':
            if len(sys.argv) != 3:
                print('Usage: python crawler.py init <db-file>',
                      file=sys.stderr)
                raise SystemExit(1)
            db_file = sys.argv[2]
            conn = sqlite3.connect(db_file,
                                   detect_types=sqlite3.PARSE_DECLTYPES)
            c = conn.cursor()
            save_links(list_pages(), c)
            conn.commit()
        elif sys.argv[1] == 'relation':
            if len(sys.argv) != 3:
                print('Usage: python crawler.py relation <db-file>',
                      file=sys.stderr)
                raise SystemExit(1)
            db_file = sys.argv[2]
            conn = sqlite3.connect(db_file,
                                   detect_types=sqlite3.PARSE_DECLTYPES)
            c = conn.cursor()
            if c.execute("SELECT name FROM sqlite_master "
                         "WHERE name='indexindex'").fetchone() is None:
                print('indexindex table is not present on provided db-file, '
                      'exiting.', file=sys.stderr)
                raise SystemExit(1)
            seed = c.execute('SELECT namespace, name, url FROM indexindex '
                             'ORDER BY namespace asc, name asc').fetchall()
            crawl_links(seed, conn)
            conn.commit()
        else:
            print(general_help_string, file=sys.stderr)
            raise SystemExit(1)
    else:
        print(general_help_string, file=sys.stderr)
        raise SystemExit(1)
<commit_msg>Improved aesthetics in relation by showing statistics every 10 cycle and skips and changed queue to stack<commit_after>import sys
import sqlite3
import urllib.parse

from datetime import datetime

from lxml.html import parse

INDEX_INDEX = 'http://tvtropes.org/pmwiki/index_report.php'
WIKI_PAGE = 'http://tvtropes.org/pmwiki/pmwiki.php/'

def list_pages(namespace_url=None):
    list_url = namespace_url or INDEX_INDEX
    print('Crawling {}'.format(list_url))
    tree = parse(list_url)

    for a in tree.xpath('//a[@class="twikilink"]'):
        name = a.text.strip()
        url = a.attrib['href']
        if namespace_url:
            yield (name,), url
        else:
            yield ('Main', name), url

    if not namespace_url:
        namespaces = tree.xpath(
            '//a[starts-with(@href, "index_report.php?groupname=")]'
        )

        for a in namespaces:
            namespace = a.text.strip()
            url = urllib.parse.urljoin(
                INDEX_INDEX, a.attrib['href']
            )
            for key, value in list_pages(url):
                assert len(key) == 1
                yield (namespace,) + key, value

def save_links(links, cur):
    cur.execute('''
        CREATE TABLE IF NOT EXISTS indexindex
        (
        namespace text, name text, url text, last_crawled timestamp,
        constraint pk_indexindex primary key(namespace, name)
        )
    ''')
    for name, url in links:
        try:
            cur.execute('INSERT INTO indexindex VALUES (?, ?, ?, NULL)',
                        (name[0], name[1], url))
        except sqlite3.IntegrityError:
            cur.execute('UPDATE indexindex SET url = ? '
                        'WHERE namespace = ? and name = ?',
                        (url, name[0], name[1]))
    print('Total {}'.format(cur.execute('SELECT count(*) FROM indexindex')
                            .fetchone()[0]))

def links_to_crawl(crawl_stack):
    while crawl_stack:
        link = crawl_stack.pop()
        if len(link) == 3:
            yield link + (None,)
        else:
            yield link

def crawl_links(crawl_stack, conn):
    c = conn.cursor()
    c.execute('''
        CREATE TABLE IF NOT EXISTS relations
        (
        origin_namespace text, origin text,
        destination_namespace text, destination text,
        constraint pk_relations primary key(origin_namespace, origin,
        destination_namespace, destination)
        )
        ''')
    start_time = datetime.now()
    start_indexindex_count = int(
        c.execute('SELECT count(*) FROM indexindex')
        .fetchone()[0])
    start_relations_count = int(
        c.execute('SELECT count(*) FROM relations')
        .fetchone()[0])
    round_count = 0
    for namespace, name, url, referer in links_to_crawl(crawl_stack):
        current_time = datetime.now()
        tree = parse(url)
        if namespace is None:
            namespace = tree.xpath('//div[@class="pagetitle"]')[0] \
                .text.strip()[:-1]
            if namespace == '':
                namespace = 'Main'
        print("Fetching: {}/{} @ {}"
              .format(namespace, name, url))
        if c.execute('SELECT count(*) FROM indexindex '
                     'WHERE namespace = ? and name = ?',
                     (namespace, name)).fetchone()[0] != 0:
            last_crawled = c.execute('SELECT last_crawled FROM indexindex '
                                     'WHERE namespace = ? and name = ?',
                                     (namespace, name)).fetchone()
            if last_crawled is not None:
                if last_crawled[0] is not None:
                    if (current_time - last_crawled[0]).days < 1:
                        print("Skipping: {}/{} @ {} due to recent crawl"
                              .format(namespace, name, url))
                        continue
        else:
            try:
                c.execute('INSERT INTO indexindex VALUES (?, ?, ?, ?)',
                          (namespace, name, url, None))
            except sqlite3.IntegrityError:
                pass
        conn.commit()
        for a in tree.xpath('//a[@class="twikilink"]'):
            try:
                destination_name = a.text.strip()
                destination_url = urllib.parse.urljoin(
                    WIKI_PAGE, a.attrib['href']
                )
                next_crawl = (None, destination_name, destination_url,
                              (namespace, name))
                if next_crawl not in crawl_stack:
                    crawl_stack.append(next_crawl)
            except AttributeError:
                pass
        if referer is not None:
            try:
                c.execute('INSERT INTO relations VALUES (?, ?, ?, ?)',
                          (referer[0], referer[1], namespace, name))
            except sqlite3.IntegrityError:
                pass
        print('Crawling {}/{} @ {} completed at {}'
              .format(namespace, name, url, current_time))
        c.execute('''
            UPDATE indexindex SET last_crawled = ?
            WHERE namespace = ? and name = ?
                ''', (current_time, namespace, name))
        round_count += 1
        if round_count >= 10:
            round_count = 0
            elasped = datetime.now() - start_time
            elasped_hours = elasped.total_seconds() / 3600
            indexindex_count = int(
                c.execute('SELECT count(*) FROM indexindex')
                .fetchone()[0]) - start_indexindex_count
            relations_count = int(
                c.execute('SELECT count(*) FROM relations')
                .fetchone()[0]) - start_relations_count
            print('-> indexindex: {} ({}/h) relations: {} ({}/h) '
                  'elasped {}'
                  .format(indexindex_count,
                          int(indexindex_count / elasped_hours),
                          relations_count,
                          int(relations_count / elasped_hours),
                          elasped))

general_help_string = '''
Usage: python crawler.py <command> <arguments>

commands:

    init:
        Usage: python crawler.py init <db-file>

        Crawls indexindex of TVTropes.
        If an entry already exists, it is updated to new url.
        If the process is inturruped in the middle, nothing will be saved.

    relation:
        Usage: python crawler.py relation <db-file>

        Crawls each pages and saves it to a table, using items in
        indexindex table as seeds. New pages are saved to indexindex table,
        and relationship of pages are saved to relations table.
        If indexindex table is not found, an error will be raised.

If a db file is not already present with each commands, one will be
automatically created.
'''.strip()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        if sys.argv[1] == 'init':
            if len(sys.argv) != 3:
                print('Usage: python crawler.py init <db-file>',
                      file=sys.stderr)
                raise SystemExit(1)
            db_file = sys.argv[2]
            conn = sqlite3.connect(db_file,
                                   detect_types=sqlite3.PARSE_DECLTYPES)
            c = conn.cursor()
            save_links(list_pages(), c)
            conn.commit()
        elif sys.argv[1] == 'relation':
            if len(sys.argv) != 3:
                print('Usage: python crawler.py relation <db-file>',
                      file=sys.stderr)
                raise SystemExit(1)
            db_file = sys.argv[2]
            conn = sqlite3.connect(db_file,
                                   detect_types=sqlite3.PARSE_DECLTYPES)
            c = conn.cursor()
            if c.execute("SELECT name FROM sqlite_master "
                         "WHERE name='indexindex'").fetchone() is None:
                print('indexindex table is not present on provided db-file, '
                      'exiting.', file=sys.stderr)
                raise SystemExit(1)
            seed = c.execute('SELECT namespace, name, url FROM indexindex '
                             'ORDER BY namespace asc, name asc').fetchall()
            crawl_links(seed, conn)
            conn.commit()
        else:
            print(general_help_string, file=sys.stderr)
            raise SystemExit(1)
    else:
        print(general_help_string, file=sys.stderr)
        raise SystemExit(1)
<|endoftext|>


<commit_before>from django.conf import settings
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site

from spreedly.models import Plan, Subscription
from spreedly.pyspreedly.api import Client

def sync_plans():
    '''
    Sync subscription plans with Spreedly API
    '''
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)

    for plan in client.get_plans():
        p, created = Plan.objects.get_or_create(speedly_id=plan['speedly_id'])

        changed = False
        for k, v in plan.items():
            if hasattr(p, k) and not getattr(p, k) == v:
                setattr(p, k, v)
                changed = True
        if changed:
            p.save()

def get_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    data = client.get_info(user.id)

    subscription, created = Subscription.objects.get_or_create(
        user=user
    )
    for k, v in data.items():
        if hasattr(subscription, k):
            setattr(subscription, k, v)
    subscription.save()
    return subscription

def create_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.get_or_create_subscriber(user.id, user.username)
    return get_subscription(user)

def get_or_create_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    data = client.get_or_create_subscriber(user.id, user.username)

    subscription, created = Subscription.objects.get_or_create(
        user=user
    )
    for k, v in data.items():
        if hasattr(subscription, k):
            setattr(subscription, k, v)
    subscription.save()
    return subscription

def check_trial_eligibility(plan, user):
    if plan.plan_type != 'free_trial':
        return False
    try:
        # make sure the user is trial eligable (they don't have a subscription yet, or they are trial_elegible)
        not_allowed = Subscription.objects.get(user=user, trial_elegible=False)
        return False
    except Subscription.DoesNotExist:
        return True

def start_free_trial(plan, user):
    if check_trial_eligibility(plan, user):
        client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
        client.get_or_create_subscriber(user.id, user.username)
        client.subscribe(user.id, plan.pk, trial=True)
        get_subscription(user)
        return True
    else:
        return False

def complimentary_time_extension(user, duration_quantity, duration_units):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.complimentary_time_extension(user.id, duration_quantity, duration_units)
    return get_subscription(user)

def complimentary_subscription(user, duration_quantity, duration_units, feature_level):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.complimentary_subscription(user.id, duration_quantity, duration_units, feature_level)
    return get_subscription(user)

def lifetime_complimentary_subscription(user, feature_level):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.lifetime_complimentary_subscription(user.id, feature_level)
    return get_subscription(user)

def add_store_credit(user, amount):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.add_store_credit(user.id, amount)
    return get_subscription(user)

def stop_auto_renew(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.stop_auto_renew(user.id)
    return get_subscription(user)

def return_url(plan, user, trial=False):
    url = 'http://%s%s' % (Site.objects.get(id=settings.SITE_ID), reverse('spreedly_return', args=[user.id, plan.pk]))
    if trial:
        url = url + '?trial=true'
    return url

def subscription_url(plan, user, return_url):
    return 'https://spreedly.com/%(site_name)s/subscribers/%(user_id)s/subscribe/%(plan_id)s/%(user_username)s?email=%(user_email)s&return_url=%(return_url)s&first_name=%(first_name)s&last_name=%(last_name)s' % {
        'site_name': settings.SPREEDLY_SITE_NAME,
        'plan_id': plan.pk,
        'user_id': user.id,
        'user_username': user.username,
        'user_email': user.email,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'return_url': return_url
    }<commit_msg>Add `allow_free_trial` function.<commit_after>from django.conf import settings
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site

from spreedly.models import Plan, Subscription
from spreedly.pyspreedly.api import Client

def sync_plans():
    '''
    Sync subscription plans with Spreedly API
    '''
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)

    for plan in client.get_plans():
        p, created = Plan.objects.get_or_create(speedly_id=plan['speedly_id'])

        changed = False
        for k, v in plan.items():
            if hasattr(p, k) and not getattr(p, k) == v:
                setattr(p, k, v)
                changed = True
        if changed:
            p.save()

def get_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    data = client.get_info(user.id)

    subscription, created = Subscription.objects.get_or_create(
        user=user
    )
    for k, v in data.items():
        if hasattr(subscription, k):
            setattr(subscription, k, v)
    subscription.save()
    return subscription

def create_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.get_or_create_subscriber(user.id, user.username)
    return get_subscription(user)

def get_or_create_subscription(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    data = client.get_or_create_subscriber(user.id, user.username)

    subscription, created = Subscription.objects.get_or_create(
        user=user
    )
    for k, v in data.items():
        if hasattr(subscription, k):
            setattr(subscription, k, v)
    subscription.save()
    return subscription

def check_trial_eligibility(plan, user):
    if plan.plan_type != 'free_trial':
        return False
    try:
        # make sure the user is trial eligable (they don't have a subscription yet, or they are trial_elegible)
        not_allowed = Subscription.objects.get(user=user, trial_elegible=False)
        return False
    except Subscription.DoesNotExist:
        return True

def start_free_trial(plan, user):
    if check_trial_eligibility(plan, user):
        client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
        client.get_or_create_subscriber(user.id, user.username)
        client.subscribe(user.id, plan.pk, trial=True)
        get_subscription(user)
        return True
    else:
        return False

def allow_free_trial(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.allow_free_trial(user.id)

def complimentary_time_extension(user, duration_quantity, duration_units):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.complimentary_time_extension(user.id, duration_quantity, duration_units)
    return get_subscription(user)

def complimentary_subscription(user, duration_quantity, duration_units, feature_level):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.complimentary_subscription(user.id, duration_quantity, duration_units, feature_level)
    return get_subscription(user)

def lifetime_complimentary_subscription(user, feature_level):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.lifetime_complimentary_subscription(user.id, feature_level)
    return get_subscription(user)

def add_store_credit(user, amount):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.add_store_credit(user.id, amount)
    return get_subscription(user)

def stop_auto_renew(user):
    client = Client(settings.SPREEDLY_AUTH_TOKEN_SECRET, settings.SPREEDLY_SITE_NAME)
    client.stop_auto_renew(user.id)
    return get_subscription(user)

def return_url(plan, user, trial=False):
    url = 'http://%s%s' % (Site.objects.get(id=settings.SITE_ID), reverse('spreedly_return', args=[user.id, plan.pk]))
    if trial:
        url = url + '?trial=true'
    return url

def subscription_url(plan, user, return_url):
    return 'https://spreedly.com/%(site_name)s/subscribers/%(user_id)s/subscribe/%(plan_id)s/%(user_username)s?email=%(user_email)s&return_url=%(return_url)s&first_name=%(first_name)s&last_name=%(last_name)s' % {
        'site_name': settings.SPREEDLY_SITE_NAME,
        'plan_id': plan.pk,
        'user_id': user.id,
        'user_username': user.username,
        'user_email': user.email,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'return_url': return_url
    }<|endoftext|>


<commit_before><commit_msg>implement body type support handling<commit_after><|endoftext|>


<commit_before>from PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLVersionProfile

from UM.Application import Application
from UM.View.Renderer import Renderer
from UM.Math.Vector import Vector
from UM.Math.Matrix import Matrix
from UM.Resources import Resources
from UM.Logger import Logger

from . import QtGL2Material

import numpy
from ctypes import c_void_p

##  A Renderer implementation using OpenGL2 to render.
class QtGL2Renderer(Renderer):
    def __init__(self):
        super().__init__()

        self._vertexBufferCache = {}
        self._indexBufferCache = {}

        self._initialized = False

        self._lightPosition = Vector(0, 0, 0)
        self._backgroundColor = QColor(128, 128, 128)
        self._viewportWidth = 0
        self._viewportHeight = 0

        self._solidsQueue = []
        self._transparentQueue = []
        self._overlayQueue = []

    def createMaterial(self, vert, frag):
        mat = QtGL2Material.QtGL2Material(self)
        mat.loadVertexShader(vert)
        mat.loadFragmentShader(frag)
        mat.build()
        return mat

    def setLightPosition(self, position):
        self._lightPosition = position

    def setBackgroundColor(self, color):
        print('setBackgroundColor')
        self._backgroundColor = color

    def setViewportSize(self, width, height):
        self._viewportWidth = width
        self._viewportHeight = height

    def beginRendering(self):
        if not self._initialized:
            self._initialize()

        self._gl.glViewport(0, 0, self._viewportWidth, self._viewportHeight)
        self._gl.glClearColor(self._backgroundColor.redF(), self._backgroundColor.greenF(), self._backgroundColor.blueF(), self._backgroundColor.alphaF())
        self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)

        self._gl.glPointSize(2)

        self._solidsQueue.clear()
        self._transparentQueue.clear()
        self._overlayQueue.clear()

    def queueMesh(self, mesh, transform, **kwargs):
        queueItem = { 'transform': transform, 'mesh': mesh }

        queueItem['material'] = kwargs.get('material', self._defaultMaterial)

        mode = kwargs.get('mode', Renderer.RenderTriangles)
        if mode is Renderer.RenderLines:
            queueItem['mode'] = self._gl.GL_LINES
        elif mode is Renderer.RenderPoints:
            queueItem['mode'] = self._gl.GL_POINTS
        elif mode is Renderer.RenderWireframe:
            queueItem['mode'] = self._gl.GL_TRIANGLES
            queueItem['wireframe'] = True
        else:
            queueItem['mode'] = self._gl.GL_TRIANGLES

        if kwargs.get('transparent', False):
            self._transparentQueue.append(queueItem)
        elif kwargs.get('overlay', False):
            self._overlayQueue.append(queueItem)
        else:
            self._solidsQueue.append(queueItem)

    def renderQueuedMeshes(self):
        self._gl.glEnable(self._gl.GL_DEPTH_TEST)
        self._gl.glDepthFunc(self._gl.GL_LESS)
        self._gl.glDepthMask(self._gl.GL_TRUE)
        self._gl.glEnable(self._gl.GL_CULL_FACE)

        for item in self._solidsQueue:
            self._renderItem(item)

        self._gl.glDepthMask(self._gl.GL_FALSE)
        self._gl.glEnable(self._gl.GL_BLEND)

        for item in self._transparentQueue:
            self._renderItem(item)

        self._gl.glDisable(self._gl.GL_DEPTH_TEST)

        for item in self._overlayQueue:
            self._renderItem(item)

    def endRendering(self):
        pass

    def _initialize(self):
        profile = QOpenGLVersionProfile()
        profile.setVersion(2, 0)
        self._gl = QOpenGLContext.currentContext().versionFunctions(profile)
        self._gl.initializeOpenGLFunctions()

        self._defaultMaterial = QtGL2Material.QtGL2Material(self)
        self._defaultMaterial.loadVertexShader(Resources.getPath(Resources.ShadersLocation, 'default.vert'))
        self._defaultMaterial.loadFragmentShader(Resources.getPath(Resources.ShadersLocation, 'default.frag'))
        self._defaultMaterial.build()

        self._defaultMaterial.setUniformValue("u_ambientColor", [0.3, 0.3, 0.3, 1.0])
        self._defaultMaterial.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 1.0])
        self._defaultMaterial.setUniformValue("u_specularColor", [1.0, 1.0, 1.0, 1.0])
        self._defaultMaterial.setUniformValue("u_shininess", 50.0)

        self._initialized = True

    def _renderItem(self, item):
        mesh = item['mesh']
        transform = item['transform']
        material = item['material']
        mode = item['mode']
        wireframe = item.get('wireframe', False)

        if mesh not in self._vertexBufferCache:
            ##TODO: Empty the cache when the meshdata gets destroyed
            vertexBuffer = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
            vertexBuffer.create()
            vertexBuffer.bind()
            vertices = mesh.getVerticesAsByteArray()

            if mesh.hasNormals():
                normals = mesh.getNormalsAsByteArray()
                ##Number of vertices * number of components (3 for vertex, 3 for normal) * size of 32-bit float (4)
                vertexBuffer.allocate(mesh.getVertexCount() * 6 * 4)
                vertexBuffer.write(0, vertices, len(vertices))
                vertexBuffer.write(len(vertices), normals, len(normals))
            else:
                vertexBuffer.allocate(vertices, mesh.getVertexCount() * 3 * 4)

            vertexBuffer.release()
            self._vertexBufferCache[mesh] = vertexBuffer

            if mesh.hasIndices():
                index_buffer = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
                index_buffer.create()
                index_buffer.bind()

                data = mesh.getIndicesAsByteArray()
                index_buffer.allocate(data, len(data))
                index_buffer.release()
                self._indexBufferCache[mesh] = index_buffer

        camera = Application.getInstance().getController().getScene().getActiveCamera()
        if not camera:
            Logger.log("e", "No active camera set, can not render")
            return

        material.bind()

        material.setUniformValue("u_projectionMatrix", camera.getProjectionMatrix(), cache = False)
        material.setUniformValue("u_viewMatrix", camera.getGlobalTransformation().getInverse(), cache = False)
        material.setUniformValue("u_viewPosition", camera.getGlobalPosition(), cache = False)
        material.setUniformValue("u_modelMatrix", transform, cache = False)
        material.setUniformValue("u_lightPosition", camera.getGlobalPosition(), cache = False)

        if mesh.hasNormals():
            normalMatrix = transform
            normalMatrix.setRow(3, [0, 0, 0, 1])
            normalMatrix.setColumn(3, [0, 0, 0, 1])
            normalMatrix = normalMatrix.getInverse().getTransposed()
            material.setUniformValue("u_normalMatrix", normalMatrix, cache = False)

        vertexBuffer = self._vertexBufferCache[mesh]
        vertexBuffer.bind()

        if mesh.hasIndices():
            indexBuffer = self._indexBufferCache[mesh]
            indexBuffer.bind()

        material.enableAttribute("a_vertex", Vector, 0)

        if mesh.hasNormals():
            material.enableAttribute("a_normal", Vector, mesh.getVertexCount() * 3 * 4)

        if wireframe:
            self._gl.glPolygonMode(self._gl.GL_FRONT_AND_BACK, self._gl.GL_LINE)

        if mesh.hasIndices():
            self._gl.glDrawElements(mode, mesh.getVertexCount(), self._gl.GL_UNSIGNED_INT, None)
        else:
            self._gl.glDrawArrays(mode, 0, mesh.getVertexCount())

        if wireframe:
            self._gl.glPolygonMode(self._gl.GL_FRONT_AND_BACK, self._gl.GL_FILL)

        material.disableAttribute("a_vertex")
        material.disableAttribute("a_normal")
        vertexBuffer.release()

        if mesh.hasIndices():
            indexBuffer.release()

        material.release()
<commit_msg>Use a property to store the vertex/index buffers on the mesh so it gets cleaned up after the mesh is removed<commit_after>from PyQt5.QtGui import QColor, QOpenGLBuffer, QOpenGLContext, QOpenGLVersionProfile

from UM.Application import Application
from UM.View.Renderer import Renderer
from UM.Math.Vector import Vector
from UM.Math.Matrix import Matrix
from UM.Resources import Resources
from UM.Logger import Logger

from . import QtGL2Material

import numpy
from ctypes import c_void_p

vertexBufferProperty = '__qtgl2_vertex_buffer'
indexBufferProperty = '__qtgl2_index_buffer'

##  A Renderer implementation using OpenGL2 to render.
class QtGL2Renderer(Renderer):
    def __init__(self):
        super().__init__()

        self._vertexBufferCache = {}
        self._indexBufferCache = {}

        self._initialized = False

        self._lightPosition = Vector(0, 0, 0)
        self._backgroundColor = QColor(128, 128, 128)
        self._viewportWidth = 0
        self._viewportHeight = 0

        self._solidsQueue = []
        self._transparentQueue = []
        self._overlayQueue = []

        self._camera = None

    def createMaterial(self, vert, frag):
        mat = QtGL2Material.QtGL2Material(self)
        mat.loadVertexShader(vert)
        mat.loadFragmentShader(frag)
        mat.build()
        return mat

    def setLightPosition(self, position):
        self._lightPosition = position

    def setBackgroundColor(self, color):
        print('setBackgroundColor')
        self._backgroundColor = color

    def setViewportSize(self, width, height):
        self._viewportWidth = width
        self._viewportHeight = height

    def beginRendering(self):
        if not self._initialized:
            self._initialize()

        self._gl.glViewport(0, 0, self._viewportWidth, self._viewportHeight)
        self._gl.glClearColor(self._backgroundColor.redF(), self._backgroundColor.greenF(), self._backgroundColor.blueF(), self._backgroundColor.alphaF())
        self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)

        if not QOpenGLContext.currentContext().isOpenGLES():
            self._gl.glPointSize(2)

        self._solidsQueue.clear()
        self._transparentQueue.clear()
        self._overlayQueue.clear()

    def queueMesh(self, mesh, transform, **kwargs):
        queueItem = { 'transform': transform, 'mesh': mesh }

        queueItem['material'] = kwargs.get('material', self._defaultMaterial)

        mode = kwargs.get('mode', Renderer.RenderTriangles)
        if mode is Renderer.RenderLines:
            queueItem['mode'] = self._gl.GL_LINES
        elif mode is Renderer.RenderPoints:
            queueItem['mode'] = self._gl.GL_POINTS
        else:
            queueItem['mode'] = self._gl.GL_TRIANGLES

        queueItem['wireframe'] = (mode == Renderer.RenderWireframe)

        if kwargs.get('transparent', False):
            self._transparentQueue.append(queueItem)
        elif kwargs.get('overlay', False):
            self._overlayQueue.append(queueItem)
        else:
            self._solidsQueue.append(queueItem)

    def renderQueuedMeshes(self):
        self._gl.glEnable(self._gl.GL_DEPTH_TEST)
        self._gl.glDepthFunc(self._gl.GL_LESS)
        self._gl.glDepthMask(self._gl.GL_TRUE)
        self._gl.glEnable(self._gl.GL_CULL_FACE)

        self._camera = Application.getInstance().getController().getScene().getActiveCamera()
        if not self._camera:
            Logger.log("e", "No active camera set, can not render")
            return

        for item in self._solidsQueue:
            self._renderItem(item)

        self._gl.glDepthMask(self._gl.GL_FALSE)
        self._gl.glEnable(self._gl.GL_BLEND)

        for item in self._transparentQueue:
            self._renderItem(item)

        self._gl.glDisable(self._gl.GL_DEPTH_TEST)

        for item in self._overlayQueue:
            self._renderItem(item)

    def endRendering(self):
        pass

    def _initialize(self):
        profile = QOpenGLVersionProfile()
        profile.setVersion(2, 0)
        self._gl = QOpenGLContext.currentContext().versionFunctions(profile)
        self._gl.initializeOpenGLFunctions()

        self._defaultMaterial = QtGL2Material.QtGL2Material(self)
        self._defaultMaterial.loadVertexShader(Resources.getPath(Resources.ShadersLocation, 'default.vert'))
        self._defaultMaterial.loadFragmentShader(Resources.getPath(Resources.ShadersLocation, 'default.frag'))
        self._defaultMaterial.build()

        self._defaultMaterial.setUniformValue("u_ambientColor", [0.3, 0.3, 0.3, 1.0])
        self._defaultMaterial.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 1.0])
        self._defaultMaterial.setUniformValue("u_specularColor", [1.0, 1.0, 1.0, 1.0])
        self._defaultMaterial.setUniformValue("u_shininess", 50.0)

        self._initialized = True

    def _renderItem(self, item):
        mesh = item['mesh']
        transform = item['transform']
        material = item['material']
        mode = item['mode']
        wireframe = item.get('wireframe', False)

        material.bind()
        material.setUniformValue("u_projectionMatrix", self._camera.getProjectionMatrix(), cache = False)
        material.setUniformValue("u_viewMatrix", self._camera.getGlobalTransformation().getInverse(), cache = False)
        material.setUniformValue("u_viewPosition", self._camera.getGlobalPosition(), cache = False)
        material.setUniformValue("u_modelMatrix", transform, cache = False)
        material.setUniformValue("u_lightPosition", self._camera.getGlobalPosition(), cache = False)

        if mesh.hasNormals():
            normalMatrix = transform
            normalMatrix.setRow(3, [0, 0, 0, 1])
            normalMatrix.setColumn(3, [0, 0, 0, 1])
            normalMatrix = normalMatrix.getInverse().getTransposed()
            material.setUniformValue("u_normalMatrix", normalMatrix, cache = False)

        try:
            vertexBuffer = getattr(mesh, vertexBufferProperty)
        except AttributeError:
            vertexBuffer =  self._createVertexBuffer(mesh)
        vertexBuffer.bind()

        if mesh.hasIndices():
            try:
                indexBuffer = getattr(mesh, indexBufferProperty)
            except AttributeError:
                indexBuffer = self._createIndexBuffer(mesh)
            indexBuffer.bind()

        material.enableAttribute("a_vertex", Vector, 0)

        if mesh.hasNormals():
            material.enableAttribute("a_normal", Vector, mesh.getVertexCount() * 3 * 4)

        if wireframe:
            self._gl.glPolygonMode(self._gl.GL_FRONT_AND_BACK, self._gl.GL_LINE)

        if mesh.hasIndices():
            self._gl.glDrawElements(mode, mesh.getVertexCount(), self._gl.GL_UNSIGNED_INT, None)
        else:
            self._gl.glDrawArrays(mode, 0, mesh.getVertexCount())

        if wireframe:
            self._gl.glPolygonMode(self._gl.GL_FRONT_AND_BACK, self._gl.GL_FILL)

        material.disableAttribute("a_vertex")
        material.disableAttribute("a_normal")
        vertexBuffer.release()

        if mesh.hasIndices():
            indexBuffer.release()

        material.release()

    def _createVertexBuffer(self, mesh):
        buffer = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        buffer.create()
        buffer.bind()
        vertices = mesh.getVerticesAsByteArray()

        if mesh.hasNormals():
            normals = mesh.getNormalsAsByteArray()
            ##Number of vertices * number of components (3 for vertex, 3 for normal) * size of 32-bit float (4)
            buffer.allocate(mesh.getVertexCount() * 6 * 4)
            buffer.write(0, vertices, len(vertices))
            buffer.write(len(vertices), normals, len(normals))
        else:
            buffer.allocate(vertices, mesh.getVertexCount() * 3 * 4)
        buffer.release()

        setattr(mesh, vertexBufferProperty, buffer)
        return buffer

    def _createIndexBuffer(self, mesh):
        buffer = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
        buffer.create()
        buffer.bind()

        data = mesh.getIndicesAsByteArray()
        buffer.allocate(data, len(data))
        buffer.release()

        setattr(mesh, indexBufferProperty, buffer)
        return buffer

<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
AppName

App Description
"""
<commit_msg>Inital connection test<commit_after>#!/usr/bin/env python
"""
Connection Test

First test to make sure all adapters can connect and disconnect properly
"""
import nose
import pika
import pika.adapters
from pika.adapters.tornado_connection import TornadoConnection

connected = False  # Global connected flag, resets in each test

HOST = 'localhost'
PORT = 5672

""" Hanging
@nose.tools.timed(2)
def test_asyncore_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'epoll'
    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = pika.adapters.AsyncoreConnection(parameters,
                                                  on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass
"""

@nose.tools.timed(2)
def test_select_epoll_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'epoll'
    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = pika.adapters.SelectConnection(parameters,
                                                on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass

@nose.tools.timed(2)
def test_select_poll_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'poll'

    print pika.adapters.select_connection.SELECT_TYPE

    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = pika.adapters.SelectConnection(parameters,
                                                on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass

@nose.tools.timed(2)
def test_select_select_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'select'
    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = pika.adapters.SelectConnection(parameters,
                                                on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass

@nose.tools.timed(2)
def test_select_kqueue_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'kqueue'
    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = pika.adapters.SelectConnection(parameters,
                                                on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass

@nose.tools.timed(2)
def test_select_tornado_connection():
    global connected
    connected = False
    pika.adapters.select_connection.SELECT_TYPE = 'epoll'
    parameters = pika.ConnectionParameters(HOST, PORT)
    connection = TornadoConnection(parameters, on_connected)
    connection.ioloop.start()
    if not connected:
        assert False
    else:
        pass

@nose.tools.nottest
def on_connected(connection):
    global connected
    connected = connection.is_open()
    connection.ioloop.stop()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

version = "2.0.4"
version_info = (2, 0, 4)

<commit_msg>release 2.0.5<commit_after># -*- coding: utf-8 -*-

version = "2.0.5"
version_info = (2, 0, 5)

<|endoftext|>


<commit_before># vim: tabstop=4 shiftwidth=4 softtabstop=4

import argparse
import getpass
import logging
import os
import os.path
import tarfile
import tempfile
import time
import yaml

import fabric.api
import fabric.operations

from cloudenvy import exceptions
from cloudenvy.envy import Envy

from cloudenvy.config import EnvyConfig

from cloudenvy.commands.envy_up import EnvyUp
from cloudenvy.commands.envy_list import EnvyList
from cloudenvy.commands.envy_provision import EnvyProvision
from cloudenvy.commands.envy_snapshot import EnvySnapshot
from cloudenvy.commands.envy_ip import EnvyIP
from cloudenvy.commands.envy_scp import EnvySCP
from cloudenvy.commands.envy_dotfiles import EnvyDotfiles
from cloudenvy.commands.envy_ssh import EnvySSH
from cloudenvy.commands.envy_destroy import EnvyDestroy

def _build_parser():
    parser = argparse.ArgumentParser(
        description='Launch a virtual machine in an openstack environment.')
    parser.add_argument('-v', '--verbosity', action='count',
                        help='increase output verbosity')
    parser.add_argument('-c', '--cloud', action='store',
                        help='specify which cloud to use')
    subparsers = parser.add_subparsers(title='Available commands:')

    # Load up all of the subparser classes
    EnvyUp(subparsers)
    EnvyList(subparsers)
    EnvyProvision(subparsers)
    EnvySnapshot(subparsers)
    EnvyIP(subparsers)
    EnvySCP(subparsers)
    EnvyDotfiles(subparsers)
    EnvySSH(subparsers)
    EnvyDestroy(subparsers)

    return parser

def main():
    parser = _build_parser()
    args = parser.parse_args()

    config = EnvyConfig(args).get_config()

    args.func(config, args)
<commit_msg>Removing imports that are no longer used<commit_after># vim: tabstop=4 shiftwidth=4 softtabstop=4

import argparse

from cloudenvy.config import EnvyConfig

from cloudenvy.commands.envy_up import EnvyUp
from cloudenvy.commands.envy_list import EnvyList
from cloudenvy.commands.envy_provision import EnvyProvision
from cloudenvy.commands.envy_snapshot import EnvySnapshot
from cloudenvy.commands.envy_ip import EnvyIP
from cloudenvy.commands.envy_scp import EnvySCP
from cloudenvy.commands.envy_dotfiles import EnvyDotfiles
from cloudenvy.commands.envy_ssh import EnvySSH
from cloudenvy.commands.envy_destroy import EnvyDestroy

def _build_parser():
    parser = argparse.ArgumentParser(
        description='Launch a virtual machine in an openstack environment.')
    parser.add_argument('-v', '--verbosity', action='count',
                        help='increase output verbosity')
    parser.add_argument('-c', '--cloud', action='store',
                        help='specify which cloud to use')
    subparsers = parser.add_subparsers(title='Available commands:')

    # Load up all of the subparser classes
    EnvyUp(subparsers)
    EnvyList(subparsers)
    EnvyProvision(subparsers)
    EnvySnapshot(subparsers)
    EnvyIP(subparsers)
    EnvySCP(subparsers)
    EnvyDotfiles(subparsers)
    EnvySSH(subparsers)
    EnvyDestroy(subparsers)

    return parser

def main():
    parser = _build_parser()
    args = parser.parse_args()

    config = EnvyConfig(args).get_config()

    args.func(config, args)
<|endoftext|>


<commit_before>import os
import unittest
from imagemounter import ImageParser

class FilesystemDirectMountTestBase(object):
    def test_mount(self):
        volumes = []
        self.filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.filename)
        parser = ImageParser([self.filename], None, False)
        for v in parser.init():
            volumes.append(v)

        parser.force_clean()

        self.validate_count(volumes)
        self.validate_types(volumes)

class CramFSDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.cramfs'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "cramfs")

class ExtDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.ext3'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "ext")

class Fat12DirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.fat12'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "fat")

class IsoDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.iso'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "iso")

class MbrDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.mbr'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 13)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].flag, "meta")
        self.assertEqual(volumes[1].flag, "unalloc")
        self.assertEqual(volumes[2].fstype, "fat")
        self.assertEqual(volumes[3].fstype, "ext")
        self.assertEqual(volumes[4].fstype, "unknown")
        self.assertEqual(volumes[5].flag, "meta")
        self.assertEqual(volumes[6].flag, "meta")
        self.assertEqual(volumes[7].flag, "unalloc")
        self.assertEqual(volumes[8].fstype, "ext")
        self.assertEqual(volumes[9].flag, "meta")
        self.assertEqual(volumes[10].flag, "meta")
        self.assertEqual(volumes[11].flag, "unalloc")
        self.assertEqual(volumes[12].fstype, "fat")

class MinixDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.minix'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "minix")

class NtfsDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.ntfs'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "ntfs")

class SquashDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.sqsh'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "squashfs")

class ZipDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.zip'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "iso")
<commit_msg>Skip test_mount for the AVFS test if no root<commit_after>import os
import unittest
from imagemounter import ImageParser

class FilesystemDirectMountTestBase(object):
    def test_mount(self):
        volumes = []
        self.filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.filename)
        parser = ImageParser([self.filename], None, False)
        for v in parser.init():
            volumes.append(v)

        parser.force_clean()

        self.validate_count(volumes)
        self.validate_types(volumes)

class CramFSDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.cramfs'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "cramfs")

class ExtDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.ext3'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "ext")

class Fat12DirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.fat12'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "fat")

class IsoDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.iso'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "iso")

class MbrDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.mbr'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 13)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].flag, "meta")
        self.assertEqual(volumes[1].flag, "unalloc")
        self.assertEqual(volumes[2].fstype, "fat")
        self.assertEqual(volumes[3].fstype, "ext")
        self.assertEqual(volumes[4].fstype, "unknown")
        self.assertEqual(volumes[5].flag, "meta")
        self.assertEqual(volumes[6].flag, "meta")
        self.assertEqual(volumes[7].flag, "unalloc")
        self.assertEqual(volumes[8].fstype, "ext")
        self.assertEqual(volumes[9].flag, "meta")
        self.assertEqual(volumes[10].flag, "meta")
        self.assertEqual(volumes[11].flag, "unalloc")
        self.assertEqual(volumes[12].fstype, "fat")

class MinixDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.minix'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "minix")

class NtfsDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.ntfs'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "ntfs")

class SquashDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.sqsh'

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "squashfs")

class ZipDirectMountTest(FilesystemDirectMountTestBase, unittest.TestCase):
    def setUp(self):
        self.filename = 'images/test.zip'

    @unittest.skipIf(os.geteuid(), "must be root to run this test")
    def test_mount(self):
        super(ZipDirectMountTest, self).test_mount()

    def validate_count(self, volumes):
        self.assertEqual(len(volumes), 1)

    def validate_types(self, volumes):
        self.assertEqual(volumes[0].fstype, "iso")
<|endoftext|>