# Autodesk APS File upload to OSS

For uploading files to OSS Bucket storage using 2-legged, you must use the "signed url via s3" upload sequence (refer to the 'signeds3upload' code below).

utils.py
```
import requests
import os
import base64

class APSClient:
    def __init__(self):
        self.client_id = os.getenv('APS_CLIENT_ID')
        self.client_secret = os.getenv('APS_CLIENT_SECRET')
        self.bucket_key = os.getenv('APS_BUCKET_KEY')
        self.base_url = 'https://developer.api.autodesk.com'
        self._token = None

    def token(self):
        if self._token:
            return self._token
        response = requests.post(f'{self.base_url}/authentication/v2/token', 
                               data={'grant_type': 'client_credentials', 'scope': 'data:read data:write bucket:create'}, 
                               auth=(self.client_id, self.client_secret))
        self._token = response.json()['access_token']
        return self._token

    def ensure_bucket(self):
        headers = {'Authorization': f'Bearer {self.token()}'}
        response = requests.get(f'{self.base_url}/oss/v2/buckets/{self.bucket_key}/details', headers=headers)
        if response.status_code in [403, 404]:
            create_headers = {**headers, 'x-ads-region': 'US'} # US, EMEA, AUS
            requests.post(f'{self.base_url}/oss/v2/buckets', 
                         json={'bucketKey': self.bucket_key, 'policyKey': 'transient'}, headers=create_headers)

    def upload(self, file_name, file_content):
        self.ensure_bucket()
        headers = {'Authorization': f'Bearer {self.token()}'}
        url = f'{self.base_url}/oss/v2/buckets/{self.bucket_key}/objects/{file_name}/signeds3upload'
        
        s3_data = requests.get(url, headers=headers).json()
        requests.put(s3_data['urls'][0], data=file_content)
        
        return requests.post(url, json={'uploadKey': s3_data['uploadKey']}, 
                           headers={**headers, 'Content-Type': 'application/json'}).json()

    def translate(self, urn):
        return requests.post(f'{self.base_url}/modelderivative/v2/designdata/job',
                           json={'input': {'urn': base64.b64encode(urn.encode()).decode()},
                                'output': {'formats': [{'type': 'svf2', 'views': ['2d', '3d']}]}},
                           headers={'Authorization': f'Bearer {self.token()}', 'Content-Type': 'application/json'}).json()

    def status(self, urn):
        encoded_urn = base64.b64encode(urn.encode()).decode()
        return requests.get(f'{self.base_url}/modelderivative/v2/designdata/{encoded_urn}/manifest',
                          headers={'Authorization': f'Bearer {self.token()}'}).json()

    def list(self):
        return requests.get(f'{self.base_url}/oss/v2/buckets/{self.bucket_key}/objects',
                          headers={'Authorization': f'Bearer {self.token()}'}).json() 
```

server.py
```
from flask import Flask, request, jsonify, send_file
from dotenv import load_dotenv
import base64
from utils import APSClient

load_dotenv()

app = Flask(__name__)
aps_client = APSClient()

@app.route('/api/token')
def get_token():
    return jsonify({'access_token': aps_client.token()})

@app.route('/api/upload', methods=['POST'])
def upload_file():
    file = request.files['file']
    result = aps_client.upload(file.filename, file.read())
    object_id = result['objectId']
    aps_client.translate(object_id)
    return jsonify({'objectId': object_id, 'urn': base64.b64encode(object_id.encode()).decode()})

@app.route('/api/status/<urn>')
def get_status(urn):
    return jsonify(aps_client.status(base64.b64decode(urn).decode()))

@app.route('/api/list')
def list_objects():
    return jsonify(aps_client.list())

@app.route('/')
def index():
    return send_file('viewer.html')

if __name__ == '__main__':
    app.run(debug=False, port=8080) 
```

---