コード例 #1
0
class Distribution(object):
    """Contains the needed functionality for Materials distribution.
	By default the distribution is manual.\n
	:param school: name of the ou
	:type school: str
	:param connection:
	:type connection: UMC connection object
	:param ucr:
	:type ucr: UCR object
	:param name: name of distribution project to be added later
	:type name: str
	:param description: description of distribution project to be added  later
	:type description: str
	:param sender: name of the creater user (teacher or admin)
	:type sender: str
	:param flavor: flavor of the acting user
	:type flavor: str ('teacher' or 'admin')
	:param distributeTime: time for automatic distribution
	:type distributeTime: str ('%I:%M')
	:param distributionDate: date for automatic distribution
	:type distributionDate: str ('%Y-%m-%d)
	:param collectionTime: time for automatic collection
	:type collectionTime: str ('%I:%M')
	:param collectionDate: date for automatic collection
	:type collectionDate: str ('%Y-%m-%d)
	:param distributeType: type of the distribution
	:type distributionType: str ('automatic' or 'manual')
	:param collectionTye: type of the collection
	:type collectionType: str ('automatic' or 'manual')
	:param files: names of material files for the distribution project
	:type files: list of str
	:param recipients: groups which are included in the distribution project
	:type recipients: list of group objects
	"""
    def __init__(self,
                 school,
                 connection=None,
                 sender=None,
                 flavor=None,
                 ucr=None,
                 description=None,
                 name=None,
                 distributeType='manual',
                 distributeTime=None,
                 distributeDate=None,
                 collectType='manual',
                 collectTime=None,
                 collectDate=None,
                 files=[],
                 recipients=[]):
        account = utils.UCSTestDomainAdminCredentials()
        admin = account.username
        passwd = account.bindpw
        self.school = school
        self.name = name if name else uts.random_string()
        self.description = description if description else uts.random_string()
        if distributeTime:
            self.distributeTime = distributeTime
        else:
            self.distributeTime = time.strftime('%I:%M')
        if distributeDate:
            self.distributeDate = distributeDate
        else:
            self.distributeDate = time.strftime('%Y-%m-%d')
        self.collectTime = collectTime if collectTime else time.strftime(
            '%I:%M')
        self.collectDate = collectDate if collectDate else time.strftime(
            '%Y-%m-%d')
        self.distributeType = distributeType
        self.collectType = collectType
        self.files = files
        self.recipients = recipients
        self.ucr = ucr if ucr else ucr_test.UCSTestConfigRegistry()
        self.sender = sender if sender else admin
        self.flavor = flavor if flavor else 'admin'
        if connection:
            self.client = connection
        else:
            self.client = Client(None, admin, passwd)

    def query(self, filt='private', pattern=''):
        """Calles 'distribution/query'
		:param pattern: the pattern to use in the search
		:type pattern: str
		"""
        flavor = self.flavor
        param = {'filter': filt, 'pattern': pattern}
        reqResult = self.client.umc_command('distribution/query', param,
                                            flavor).result
        result = [x['name'] for x in reqResult if reqResult is not None]
        return result

    def get(self):
        """Calls 'distribute/get'"""
        name = [self.name]
        reqResult = self.client.umc_command('distribution/get', name,
                                            self.flavor).result
        return reqResult[0]

    def idir(self, path):
        """Dir a specific path.\n
		:param path: wanted path
		:type path: str
		:return: list of file names
		"""
        files = []
        for root, _, filenames in os.walk(path):
            for f in filenames:
                files.append(os.path.relpath(os.path.join(root, f), path))
        return files

    def genData(self, file_name, content_type, boundary, flavor):
        """Generates data in the form to be sent via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str ('text/plain',..)
		:param boundary: the boundary
		:type boundary: str (-------123091)
		:param flavor: flavor of the acting user
		:type flavor: str
		"""
        with open(file_name, 'r') as f:
            data = r"""--{0}
Content-Disposition: form-data; name="uploadedfile"; filename="{1}"
Content-Type: {2}

{3}
--{0}
Content-Disposition: form-data; name="flavor"

{4}
--{0}
Content-Disposition: form-data; name="iframe"

false
--{0}
Content-Disposition: form-data; name="uploadType"

html5
--{0}--
""".format(boundary, file_name, content_type, f.read(), flavor)
        return data.replace("\n", "\r\n")

    def uploadFile(self, file_name, content_type):
        """Uploads a file via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str ('text/plain',..)
		"""
        print 'Uploading a file'
        boundary = '---------------------------103454444410473823401882756'
        data = self.genData(file_name, content_type, boundary, self.flavor)
        header_content = {
            'Content-Type': 'multipart/form-data; boundary=%s' % (boundary, )
        }
        self.client.request('POST',
                            'upload/distribution/upload',
                            data,
                            headers=header_content).result

    def add(self):
        """Create files and upload them then add the project,
		calls: 'distribution/add'
		"""
        # creatng and uploading the files
        content_type = 'text/plain'
        for filename, encoding in self.files:
            with open(filename, 'w') as g:
                g.write('test_content')
            self.uploadFile(filename, content_type)
        print 'Adding Project %s' % (self.name)
        flavor = self.flavor
        recipients = []
        for item in self.recipients:
            recipients.append(item.dn())
        print 'recipients=', recipients
        files = [
            file_name.decode(encoding).encode('UTF-8')
            for file_name, encoding in self.files
        ]
        param = [{
            'object': {
                'collectDate': self.collectDate,
                'collectTime': self.collectTime,
                'collectType': self.collectType,
                'description': self.description,
                'distributeDate': self.distributeDate,
                'distributeTime': self.distributeTime,
                'distributeType': self.distributeType,
                'files': files,
                'name': self.name,
                'recipients': recipients
            },
            'options': None
        }]
        print 'param=', param
        reqResult = self.client.umc_command('distribution/add', param,
                                            flavor).result
        print 'reqResult =', reqResult
        if not reqResult[0]['success']:
            utils.fail('Unable to add project (%r)' % (param, ))

    def check_add(self):
        """Calls 'distribution/query'
		and check the existance of the added project
		"""
        print 'Checking %s addition' % (self.name, )
        current = self.query(pattern=self.name)
        if not (self.name in current):
            utils.fail('Project %s was not added successfully' % (self.name, ))

    def put(self,
            description=None,
            distributeType=None,
            distributeTime=None,
            distributeDate=None,
            collectType=None,
            collectTime=None,
            collectDate=None,
            files=[],
            recipients=[]):
        """Modifies the already existing project.\n
		:param description: description of the project to be added later
		:type description: str
		:param distributeTime: time for automatic distribution
		:type distributeTime: str ('%I:%M')
		:param distributionDate: date for automatic distribution
		:type distributionDate: str ('%Y-%m-%d)
		:param collectionTime: time for automatic collection
		:type collectionTime: str ('%I:%M')
		:param collectionDate: date for automatic collection
		:type collectionDate: str ('%Y-%m-%d)
		:param distributeType: type of the distribution
		:type distributionType: str ('automatic' or 'manual')
		:param collectionTye: type of the collection
		:type collectionType: str ('automatic' or 'manual')
		:param files: names of material files for the distribution project
		:type files: list of str
		:param recipients: groups which are included in the project
		:type recipients: list of group objects
		"""
        print 'Editing Project %s' % (self.name)
        description = description if description else self.description
        if distributeType:
            distributeType = distributeType
        else:
            distributeType = self.distributeType
        if distributeTime:
            distributeTime = distributeTime
        else:
            distributeTime = self.distributeTime
        if distributeDate:
            distributeDate = distributeDate
        else:
            distributeDate = self.distributeDate
        collectType = collectType if collectType else self.collectType
        collectTime = collectTime if collectTime else self.collectTime
        collectDate = collectDate if collectDate else self.collectDate
        files = files if files else [x for x, y in self.files]
        recipients = recipients if recipients else self.recipients
        new_recipients = []
        for item in recipients:
            new_recipients.append(item.dn())
        flavor = self.flavor
        param = [{
            'object': {
                'collectDate': collectDate,
                'collectTime': collectTime,
                'collectType': collectType,
                'description': description,
                'distributeDate': distributeDate,
                'distributeTime': distributeTime,
                'distributeType': distributeType,
                'files': files,
                'name': self.name,
                'recipients': new_recipients
            },
            'options': None
        }]
        reqResult = self.client.umc_command('distribution/put', param,
                                            flavor).result
        print 'reqResult =', reqResult
        if not reqResult[0]['success']:
            utils.fail('Unable to edit project with params =(%r)' % (param, ))
        else:
            self.description = description
            self.distributeType = distributeType
            self.distributeTime = distributeTime
            self.distributeDate = distributeDate
            self.collectType = collectType
            self.collectTime = collectTime
            self.collectDate = collectDate
            self.files = [(x, 'utf8') for x in files]
            self.recipients = recipients

    def check_put(self, previousGetResult):
        """Calls 'distribution/get' and check the modified project
		:param previousGetResult: info from previous get
		:type previousGetResult: dict
		check changing sates for distribution and collection
		"""
        print 'Checking %s modification' % (self.name, )
        found = self.get()
        supposed = {
            'files': found['files'],
            'sender': found['sender'],
            'description': found['description'],
            'recipients': found['recipients'],
            'distributeType': found['distributeType'],
            '__type__': found['__type__'],
            'collectType': found['collectType'],
            'name': found['name'],
            'starttime': found['starttime'],
            'deadline': found['deadline']
        }
        recips = [{'id': y.dn(), 'label': y.name} for y in self.recipients]

        if self.distributeType != 'automatic':
            sTime = None
        else:
            sTime = '%s %s' % (self.distributeDate, self.distributeTime)
        if self.collectType != 'automatic':
            dTime = None
        else:
            dTime = '%s %s' % (self.collectDate, self.collectTime)
        current = {
            'files': [x for x, y in self.files],
            'sender': self.sender,
            'description': self.description,
            'recipients': recips,
            'distributeType': self.distributeType,
            '__type__': 'PROJECT',
            'collectType': self.collectType,
            'name': self.name,
            'starttime': sTime,
            'deadline': dTime,
        }
        print 'supposed = ', supposed
        print 'current = ', current

        fail_state = supposed != current
        if fail_state:
            utils.fail(
                'Project %s was not modified successfully,supposed!=current' %
                (self.name, ))

        # check distribute
        check = 'distribution'
        before_type = previousGetResult['distributeType']
        after_type = found['distributeType']
        before_time = previousGetResult['starttime']
        after_time = found['starttime']
        before_atJob = previousGetResult['atJobNumDistribute']
        after_atJob = found['atJobNumDistribute']
        fail_state = fail_state or self.put_fail(
            before_type, after_type, before_time, after_time, before_atJob,
            after_atJob)
        if fail_state:
            utils.fail(
                'Project %s was not modified successfully, %s: %s -> %s' %
                (self.name, check, before_type, after_type))

        # check collect
        check = 'collection'
        before_type = previousGetResult['collectType']
        after_type = found['collectType']
        before_time = previousGetResult['deadline']
        after_time = found['deadline']
        before_atJob = previousGetResult['atJobNumCollect']
        after_atJob = found['atJobNumCollect']
        fail_state = fail_state or self.put_fail(
            before_type, after_type, before_time, after_time, before_atJob,
            after_atJob)
        if fail_state:
            utils.fail(
                'Project %s was not modified successfully, %s: %s -> %s' %
                (self.name, check, before_type, after_type))

    def put_fail(self, before_type, after_type, before_time, after_time,
                 before_atJob, after_atJob):
        """Checks if the atjobs are in the expected formats
		:param before_type: type before using put command
		:type before_type: str
		:param after_type: type after using put command
		:type after_type: str
		:param before_atJob: atJobNum before using put command
		:type before_atJob: str or None
		:param after_atJob: atJobNum after using put command
		:type after_atJob: str or None
		:param before_time: time before using put command
		:type before_time: str
		:param after_time: time after using put command
		:type after_time: str
		"""
        fail_state = False
        # manual -> manual
        # atJobs == don't care
        if before_type == 'manual' and after_type == 'manual':
            pass

        # manual -> automatic
        # atJobs don't care -> int
        if before_type == 'manual' and after_type == 'automatic':
            fail_state = not (isinstance(after_atJob, (int, long)))

        # automatic -> manual
        # atJobs int -> don't care
        if before_type == 'automatic' and after_type == 'manual':
            fail_state = not (isinstance(before_atJob, (int, long)))

        # automatic -> automatic
        # atJobs int1 -> int2 & int1 < int2
        if before_type == 'automatic' and after_type == 'automatic':
            fail1 = not (isinstance(before_atJob, (int, long))
                         and isinstance(after_atJob, (int, long)))
            fail2 = not (before_time != after_time and
                         (before_atJob < after_atJob))
            fail_state = fail1 or fail2
        return fail_state

    def distribute(self):
        """Calls 'distribution/distribute'"""
        print 'Distributing Project %s' % (self.name)
        flavor = self.flavor
        reqResult = self.client.umc_command('distribution/distribute',
                                            [self.name], flavor).result
        if not reqResult[0]['success']:
            utils.fail('Unable to distribute project (%r)' % (self.name, ))

    def check_distribute(self, users):
        """Checks if the distribution was successful
		by checking the file system.\n
		:param users: names of users to have the material distributed for
		:type users: list of str
		"""
        print 'Checking %s distribution' % (self.name, )
        for user in users:
            path = self.getUserFilesPath(user, 'distribute')
            print 'file_path=', path
            existingFiles = self.idir(path)
            print 'existingFiles=', existingFiles
            files = [x for x, y in self.files]
            if files != existingFiles:
                utils.fail('Project files were not distributed for user %s' %
                           (user, ))

    def collect(self):
        """Calls 'distribution/collect'"""
        print 'Collecting Project %s' % (self.name)
        flavor = self.flavor
        reqResult = self.client.umc_command('distribution/collect',
                                            [self.name], flavor).result
        if not reqResult[0]['success']:
            utils.fail('Unable to collect project (%r)' % (self.name, ))

    def check_collect(self, users):
        """Checks if the collection was successful
		by checking the file system.\n
		:param users: names of users to have the material collected form
		:type users: list of str
		"""
        print 'Checking %s collection' % (self.name, )
        for user in users:
            path = self.getUserFilesPath(user, 'collect')
            print 'file_path=', path
            existingFiles = self.idir(path)
            print 'existingFiles=', existingFiles
            files = [x for x, y in self.files]
            if files != existingFiles:
                utils.fail('Project files were not collected for user %s' %
                           (user, ))

    def remove(self):
        """Calls 'distribution/remove'"""
        print 'Removing Project %s' % (self.name)
        flavor = self.flavor
        param = [{'object': self.name, 'options': None}]
        reqResult = self.client.umc_command('distribution/remove', param,
                                            flavor).result
        if reqResult:
            utils.fail('Unable to remove project (%r)' % (param, ))

    def check_remove(self):
        """Calls 'distribution/query'
		and check the existance of the removed project
		"""
        print 'Checking %s removal' % (self.name, )
        current = self.query(pattern=self.name)
        if self.name in current:
            utils.fail('Project %s was not removed successfully' %
                       (self.name, ))

    def checkFiles(self, files):
        """Calls 'distribution/checkfiles'"""
        print 'Checking files Project %s' % (self.name)
        flavor = self.flavor
        param = {'project': self.name, 'filenames': files}
        reqResult = self.client.umc_command('distribution/checkfiles', param,
                                            flavor).result
        if reqResult:
            utils.fail('Unable to chack files for project (%r)' % (param, ))

    def adopt(self, project_name):
        """Calls 'distribute/adopt'"""
        print 'Adopting project', self.name
        flavor = self.flavor
        reqResult = self.client.umc_command('distribution/adopt',
                                            [project_name], flavor).result
        if reqResult:
            utils.fail('Failed to adopt project (%r)' % (project_name, ))

    def check_adopt(self, project_name):
        print 'Checking adopting'
        q = self.query(pattern=project_name)
        if not (project_name in q):
            utils.fail('Project %s was not adopted successfully' %
                       (project_name, ))

    def getUserFilesPath(self, user, purpose='distribute'):
        """Gets the correct files path for a specific user depending on
		the value of the ucr variable ucsschool/import/roleshare.\n
		:param user: user name
		:type user: str
		:param purpose: either for distribution or collection
		:type purpose: str ('distribute' or 'collect')
		"""
        path = ''
        self.ucr.load()
        roleshare = self.ucr.get('ucsschool/import/roleshare')
        sender_dir_name = self.ucr.get(
            'ucsschool/datadistribution/datadir/sender', 'Unterrichtsmaterial')
        project_dir_suffix = self.ucr.get(
            'ucsschool/datadistribution/datadir/sender/project/suffix',
            '-Ergebnisse')
        recipient_dir_name = self.ucr.get(
            'ucsschool/datadistribution/datadir/recipient',
            'Unterrichtsmaterial')
        if purpose == 'distribute':
            if roleshare == 'no' or roleshare is False:
                path = '/home/{0}/{1}/{2}/'.format(user, recipient_dir_name,
                                                   self.name)
            else:
                path = '/home/{0}/schueler/{1}/{2}/{3}'.format(
                    self.school, user, recipient_dir_name, self.name)
        elif purpose == 'collect':
            if roleshare == 'no' or roleshare is False:
                path = '/home/{0}/{1}/{2}{3}/{4}/'.format(
                    self.sender, sender_dir_suffix, self.name,
                    project_dir_name, user)
            else:
                path = '/home/{0}/lehrer/{1}/{2}/{3}{4}/{5}'.format(
                    self.school, self.sender, sender_dir_name, self.name,
                    project_dir_suffix, user)
        return path
コード例 #2
0
ファイル: importcsv.py プロジェクト: spaceone/ucs-school
class CSVImport(object):
    """CSVImport class, inclues all the needed operations to perform a user import"""
    def __init__(self, school, user_type):
        self.school = school
        self.user_type = user_type
        self.ucr = ucr_test.UCSTestConfigRegistry()
        self.ucr.load()
        host = self.ucr.get('hostname')
        self.client = Client(host)
        account = utils.UCSTestDomainAdminCredentials()
        admin = account.username
        passwd = account.bindpw
        self.client.authenticate(admin, passwd)

    def genData(self, boundary, file_name, content_type, school, user_type,
                delete_not_mentioned):
        """Generates data in the form to be sent via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str  = 'text/csv'
		:param boundary: the boundary
		:type boundary: str (-------123091)
		:param flavor: flavor of the acting user
		:type flavor: str
		"""
        with open(file_name, 'r') as f:
            if delete_not_mentioned:
                data = r"""--{0}
Content-Disposition: form-data; name="uploadedfile"; filename="{1}"
Content-Type: {2}

{3}
--{0}
Content-Disposition: form-data; name="school"

{4}
--{0}
Content-Disposition: form-data; name="type"

{5}
--{0}
Content-Disposition: form-data; name="delete_not_mentioned"

true
--{0}
Content-Disposition: form-data; name="iframe"

false
--{0}
Content-Disposition: form-data; name="uploadType"

html5
--{0}--
""".format(boundary, file_name, content_type, f.read(), school, user_type)
            else:
                data = r"""--{0}
Content-Disposition: form-data; name="uploadedfile"; filename="{1}"
Content-Type: {2}

{3}
--{0}
Content-Disposition: form-data; name="school"

{4}
--{0}
Content-Disposition: form-data; name="type"

{5}
--{0}
Content-Disposition: form-data; name="iframe"

false
--{0}
Content-Disposition: form-data; name="uploadType"

html5
--{0}--
""".format(boundary, file_name, content_type, f.read(), school, user_type)
        return data.replace("\n", "\r\n")

    def uploadFile(self, file_name, content_type, delete_not_mentioned,
                   expected_upload_status):
        """Uploads a file via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str ('text/csv')
		"""
        print 'Uploading file %r' % file_name
        boundary = '---------------------------18209455381072592677374099768'
        data = self.genData(boundary, file_name, content_type, self.school,
                            self.user_type, delete_not_mentioned)

        header_content = {
            'Content-Type': 'multipart/form-data; boundary=%s' % (boundary, )
        }

        try:
            response = self.client.request('POST',
                                           'upload/schoolcsvimport/save',
                                           data,
                                           headers=header_content)
        except HTTPError as exc:
            response = exc.response
        status = response.status
        if status != expected_upload_status:
            raise FailHTTPStatus('Unexpected response status=%r' % status)
        elif status == 200:
            self.file_id = response.result[0]['file_id']
            self.id_nr = 1
        else:
            print 'Expected http_status = %r' % status
        return status

    def show(self):
        param = {
            'file_id':
            self.file_id,
            'columns': [
                "name", "firstname", "lastname", "birthday", "password",
                "email", "school_classes"
            ],
        }
        if self.user_type == 'staff':
            param['columns'].remove('school_classes')
        try:
            reqResult = self.client.umc_command('schoolcsvimport/show',
                                                param).result
            self.id_nr = reqResult['id']
        except FailShow:
            raise

    def progress(self):
        param = {'progress_id': self.id_nr}
        try:
            reqResult = self.client.umc_command('schoolcsvimport/progress',
                                                param).result
        except FailProgress:
            raise
        return reqResult

    def recheck(self, user):
        param = {'file_id': self.file_id, 'user_attrs': [user]}
        try:
            reqResult = self.client.umc_command('schoolcsvimport/recheck',
                                                param).result
            print 'RECHECK RESULT = ', reqResult
            return reqResult
        except FailRecheck:
            raise

    def schools(self):
        try:
            reqResult = self.client.umc_command('schoolcsvimport/schools',
                                                {}).result
        except FailSchools:
            raise
        return [x['id'] for x in reqResult]

    def check_schools(self):
        if self.school not in self.schools():
            raise FailSchools(
                'School %s not found by request: schoolcsvimport/schools' %
                (self.school))

    def write_import_file(self, filename, lines, has_header=True):
        with open(filename, 'wb') as f:
            f.write(''.join(lines))
            f.flush()

    def read_import_file(self, filename, has_header=True):
        with open(filename, 'rb') as f:
            lines = f.readlines()
        if has_header:
            columns = lines[0][:-1].split(',')
            lines = lines[1:]
        else:
            columns = []
        lines = [x[:-1] for x in lines]
        return lines, columns

    def import_users(self, users):
        line_nr = 1
        param = []

        def get_type_name(typ):
            if typ == 'cSVStudent':
                return 'Student'
            elif typ == 'cSVTeacher':
                return 'Teacher'
            elif typ == 'cSVStaff':
                return 'Staff'
            elif typ == 'cSVTeachersAndStaff':
                return 'Teacher and Staff'

        for user in users:
            user.update({'line': line_nr})
            user.update({'type_name': get_type_name(user['type'])})
            options = {'file_id': self.file_id, 'attrs': user}
            line_nr += 1
            param.append(options)
        try:
            pprint(('Importing users with parameters=', param))
            reqResult = self.client.umc_command('schoolcsvimport/import',
                                                param).result
            self.id_nr = reqResult['id']
            utils.wait_for_replication()
        except FailImport:
            raise