def merge_metadata(self,
                       schema_uid,
                       source_object_uid,
                       target_object_uid,
                       dry_run=False):
        url = '/v5/metadata/'
        source_params = {
            'object_ids': source_object_uid,
            'schema_id': schema_uid
        }
        source_obj_resp = get_object(self.api_key, url, source_params)
        if not source_obj_resp['meta']['total']:
            print('No source metadata for {} {}'.format(
                schema_uid, source_object_uid))
            return
        source_metadata = source_obj_resp['data'][0]

        check_params = {
            'object_ids': target_object_uid,
            'schema_id': schema_uid
        }
        md_obj_resp = get_object(self.api_key, url, check_params)
        md_obj_exists = md_obj_resp['meta']['total']
        for field in ('created_at', 'updated_at', 'id'):
            del source_metadata[field]
        source_metadata['object_id'] = target_object_uid
        if not md_obj_exists:
            if dry_run:
                print('POST {} to {}'.format(source_object_uid,
                                             target_object_uid))
                pprint(source_metadata)
            else:
                post_object(self.api_key, url, source_metadata)
        else:
            existing_md = md_obj_resp['data'][0]['ext']
            adding_md = source_metadata['ext']
            schema = self._get_schema(schema_uid)
            new_md = {}
            for field in schema['fields']:
                if field['type'] == 'term' and field['ext']['limit'] is None:
                    key = field['key']
                    # TODO - associate to empty value of schema field dynamically
                    existing = existing_md.get(key, [])
                    adding = adding_md.get(key, [])
                    new_md[key] = list(set(existing) | set(adding))
            new_md_obj = {
                'object_id': target_object_uid,
                'schema_id': schema_uid,
                'ext': new_md
            }
            md_obj_id = md_obj_resp['data'][0]['id']
            if dry_run:
                print('PUT {} to {} ({})'.format(source_object_uid,
                                                 target_object_uid, md_obj_id))
                pprint(new_md_obj)
            else:
                put_object(self.api_key, url + md_obj_id, new_md_obj)
    def update_metadata(self, object_uid, metadata_dict):
        existing_metadata = get_object(self.api_key, '/v5/metadata/',
                                       {'object_ids': object_uid})['data']
        asset_metadata_id = next((x['id'] for x in existing_metadata
                                  if x['schema_id'] == self.asset_schema_uid),
                                 None)
        usage_metadata_id = next((x['id'] for x in existing_metadata
                                  if x['schema_id'] == self.usage_schema_uid),
                                 None)

        asset_metadata = {
            'schema_id': self.asset_schema_uid,
            'object_id': object_uid,
            'ext': {
                'title': metadata_dict['Title'],
                'description': metadata_dict['Description'],
            }
        }
        if metadata_dict['Tags']:
            tags = self._prepare_tags(
                [tag.strip() for tag in metadata_dict['Tags'].split(',')])
            asset_metadata['ext']['tags'] = tags
        else:
            asset_metadata['ext']['tags'] = []

        if asset_metadata_id:
            md_url = '/v5/metadata/{}'.format(asset_metadata_id)
            put_object(self.api_key, md_url, asset_metadata)
        else:
            md_url = '/v5/metadata/'
            post_object(self.api_key, md_url, asset_metadata)

        if metadata_dict['Add Usage Rights Information'] and \
                metadata_dict['Add Usage Rights Information'] not in\
                ('No', 'no', 'NO', '0'):
            usage_metadata = {
                'schema_id': self.usage_schema_uid,
                'object_id': object_uid,
            }
            uri = {}
            translation = {
                'License Type': 'title',
                'Usage Rights Information': 'description',
                'Expiration Date': 'expiration'
            }
            for f in translation.keys():
                uri[translation[f]] = metadata_dict[f]
            usage_metadata['ext'] = uri

            if usage_metadata_id:
                md_url = '/v5/metadata/{}'.format(usage_metadata_id)
                put_object(self.api_key, md_url, usage_metadata)
            else:
                md_url = '/v5/metadata/'
                post_object(self.api_key, md_url, usage_metadata)
 def copy_metadata(self, schema_uid, source_object_uid, target_object_uid):
     source_params = {
         'object_ids': source_object_uid,
         'schema_id': schema_uid
     }
     check_params = {
         'object_ids': target_object_uid,
         'schema_id': schema_uid
     }
     url = '/v5/metadata/'
     source_metadata_resp = get_object(self.api_key, url, source_params)
     if source_metadata_resp['meta']['total'] == 0:
         print('No metadata for schema {} on object {}'.format(
             schema_uid, source_object_uid))
         return None
     source_metadata = source_metadata_resp['data'][0]
     md_obj_resp = get_object(self.api_key, url, check_params)
     md_obj_exists = md_obj_resp['meta']['total']
     for field in ('created_at', 'updated_at', 'id'):
         del source_metadata[field]
     source_metadata['object_id'] = target_object_uid
     if md_obj_exists:
         md_obj_id = md_obj_resp['data'][0]['id']
         put_object(self.api_key, url + md_obj_id, source_metadata)
         result = md_obj_id
     else:
         response = post_object(self.api_key, url, source_metadata)
         result = response['id']
     return result
    def update_custom_metadata(self,
                               object_uid,
                               metadata_dict,
                               tag_path_terms=False):
        new_metadata = self._create_metadata(metadata_dict, object_uid,
                                             tag_path_terms)

        # New method
        existing_metadata = get_object(self.api_key, '/v5/metadata/',
                                       {'object_ids': object_uid})['data']
        custom_metadata = [
            x for x in existing_metadata
            if x['schema_id'] not in (self.asset_schema_uid,
                                      self.usage_schema_uid)
        ]
        payloads = {}
        metadata_id_for_schema = {}
        for x in custom_metadata:
            payloads[x['schema_id']] = x['ext']
            metadata_id_for_schema[x['schema_id']] = x['id']
        for schema_id, fields_dict in new_metadata.items():
            if schema_id not in payloads:
                payloads[schema_id] = {}
                # Schema not in existing custom metadata, but it can be created.
                # payload['schemas'].append({'schema_uid': schema_id, 'data': {}})
                # s_index = len(payload['schemas']) - 1
            for key, new_value in fields_dict.items():
                payloads[schema_id][key] = new_value
        for schema_id, ext in payloads.items():
            new_payload = {
                'schema_id': schema_id,
                'object_id': object_uid,
                'ext': ext
            }

            if schema_id in metadata_id_for_schema:
                if schema_id not in new_metadata:
                    continue
                m_id = metadata_id_for_schema[schema_id]
                put_object(self.api_key, '/v5/metadata/{}'.format(m_id),
                           new_payload)
            else:
                post_object(self.api_key, '/v5/metadata/', new_payload)
 def _prepare_tags(self, tags_list):
     term_ids = []
     for tag in tags_list:
         if tag.startswith('term:'):
             term_ids.append(tag)
             continue
         # cache_stats['count'] += 1
         if tag[:64] in self.tag_cache:
             term_ids.append(self.tag_cache[tag[:64]])
             # cache_stats['cache'] += 1
         else:
             data = {
                 'scope_id': self.license_uid,
                 'namespace': 'tag',
                 'name': tag[:64]
             }
             response = post_object(self.api_key, '/v5/term/', data)
             term_ids.append(response['id'])
             self.tag_cache[tag[:64]] = response['id']
     return term_ids
    def create_custom_metadata(self,
                               schema_id,
                               metadata_dict,
                               tag_path_terms=False):
        schema_id_list = [schema_id]
        schema_list = self._get_custom_fields(schema_uids=schema_id_list)
        info_for_field = {}
        result = {}
        for s in schema_list:
            for f in s[1]:
                info_for_field[f['label']] = f
                info_for_field[f['label']]['schema_uid'] = s[0]
        for key, value in metadata_dict.items():
            key_info = info_for_field.get(key)
            if not key_info:
                continue
            new_value = value
            # Map select to value
            if key_info['type'] == 'select':
                # all_values = map(str.strip, new_value.split('|'))
                value_for_label = {}
                for x in key_info['ext']['values']:
                    value_for_label[x['label']] = x['value']
                new_value = value_for_label.get(new_value)

            # Map multi-select to value
            if key_info['type'] == 'multi-select':
                # all_values = map(str.strip, new_value.split('|'))
                all_values = new_value.split('|')
                value_for_label = {}
                for x in key_info['ext']['values']:
                    value_for_label[x['label']] = x['value']
                new_value = [
                    value_for_label.get(x) for x in all_values
                    if value_for_label.get(x) is not None
                ]

            # Map string-array to list
            if key_info['type'] == 'string-array':
                all_values = new_value.split('|')
                all_values = [x for x in all_values if x]
                new_value = all_values

            # Map asset to list
            if key_info['type'] == 'asset':
                all_values = new_value.split(',')
                all_values = [x for x in all_values if x.startswith('asset:')]
                new_value = all_values

            # Map date to date format
            if key_info['type'] == 'date':
                try:
                    date_value = parse(new_value)
                    if key_info['ext']['include_time']:
                        time_format = '%Y-%m-%dT%H:%M:%S.000Z'
                        new_value = date_value.strftime(time_format)
                    else:
                        new_value = date_value.date().isoformat()
                except ValueError:
                    new_value = None

            # Validate link
            if key_info['type'] == 'link':
                if not isinstance(new_value, list):
                    all_values = [new_value]
                else:
                    all_values = new_value
                val = URLValidator()
                good_values = []
                for x in all_values:
                    try:
                        val(x)
                        good_values.append(x)
                    except ValidationError:
                        pass
                good_link_objs = []
                for l in good_values:
                    link_params = {'url': l}
                    link_obj = post_object(self.api_key,
                                           '/v3/links/',
                                           data=link_params)
                    good_link_objs.append('link:{}'.format(link_obj['id']))
                new_value = good_link_objs

            # Map path to term for taxonomies
            if key_info['type'] == 'term':
                root_id = key_info['ext']['parent_term_ids'][0]
                all_values = new_value.split('||') if new_value else []
                # if not isinstance(new_value, list):
                #     new_value = [new_value]
                if tag_path_terms:
                    new_value = []
                    for x in all_values:
                        if self.taxonomies[root_id].get(x) is not None:
                            new_value.extend(
                                self.taxonomies[root_id].get(x)['path'])
                    # new_value = [self.taxonomies[root_id].get(x)['path']
                    #              for x in all_values
                    #              if self.taxonomies[root_id].get(x) is not None]
                else:
                    new_value = [
                        self.taxonomies[root_id].get(x)['leaf']
                        for x in all_values
                        if self.taxonomies[root_id].get(x) is not None
                    ]
            result[key_info['key']] = new_value
        return result