Ejemplo n.º 1
0
def lab_tests(request):
    """Get lab tests for a given license number."""

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        return Response({'error': True, 'message': AUTH_ERROR}, status=403)
    _, project_id = google.auth.default()
    license_number = request.query_params.get('license')
    org_id = request.query_params.get('org_id')
    version_id = request.query_params.get('version_id')
    if not license_number or not org_id:
        message = 'Parameters `license` and `org_id` are required.'
        return Response({'error': True, 'message': message}, status=403)

    # Initialize Metrc.
    track = initialize_metrc(project_id, license_number, version_id)

    # Get lab results.
    if request.method == 'GET':
        # FIXME: Get a longer list of lab results from Firestore
        objs = track.get_lab_results(uid='185436',
                                     license_number=license_number)
        data = [obj.to_dict() for obj in objs]
        return Response({'data': data}, content_type='application/json')
Ejemplo n.º 2
0
def organization_team(request, organization_id=None, user_id=None):
    """Get team member data for an organization, given an authenticated
    request from a member of the organization.
    """
    claims = authenticate_request(request)
    print('Claims:', claims)
    try:
        if organization_id in claims['team']:
            organization_data = get_document(
                f'organizations/{organization_id}')
            team = organization_data['team']
            team_members = []
            if user_id:
                team = [user_id]
            for uid in team:
                team_member = get_document(f'users/{uid}')
                team_members.append(team_member)
            return Response({'data': team_members},
                            content_type='application/json')
        else:
            message = 'You are not a member of the requested organization.'
            return Response({'error': True, 'message': message}, status=403)
    except KeyError:
        message = 'You are not a member of any teams. Try authenticating.'
        return Response({'error': True, 'message': message}, status=401)
Ejemplo n.º 3
0
def transfers(request):
    """Get, update, and delete transfers for a given license number."""

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        return Response({'error': True, 'message': AUTH_ERROR}, status=403)

    # Get the parameters.
    _, project_id = google.auth.default()
    license_number = request.query_params.get('license')
    org_id = request.query_params.get('org_id')
    version_id = request.query_params.get('version_id')
    if not license_number or not org_id:
        message = 'Parameters `license` and `org_id` are required.'
        return Response({'error': True, 'message': message}, status=403)

    # Initialize Metrc.
    track = initialize_metrc(project_id, license_number, version_id)

    # Get data.
    if request.method == 'GET':
        # TODO: Add filters
        # uid=''
        # transfer_type='incoming'
        # license_number=''
        # start=''
        # end=''
        # FIXME: Get transfers by specified date range? Or get longer list from Firestore.
        objs = track.get_transfers(license_number=license_number,
                                   start='2021-06-04',
                                   end='2021-06-05')
        data = [obj.to_dict() for obj in objs]
        print('Retrieved the data:', data)
        return Response({'data': data}, content_type='application/json')
Ejemplo n.º 4
0
def packages(request):
    """Get, update, and delete packages for a given license number."""

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        return Response({'error': True, 'message': AUTH_ERROR}, status=403)

    # Get the parameters.
    _, project_id = google.auth.default()
    license_number = request.query_params.get('license')
    org_id = request.query_params.get('org_id')
    version_id = request.query_params.get('version_id')
    if not license_number or not org_id:
        message = 'Parameters `license` and `org_id` are required.'
        return Response({'error': True, 'message': message}, status=403)

    # Initialize Metrc.
    track = initialize_metrc(project_id, license_number, version_id)

    # Get data.
    if request.method == 'GET':
        # FIXME: Get a longer list of packages from Firestore?
        objs = track.get_packages(license_number=license_number,
                                  start='2021-06-04',
                                  end='2021-06-05')
        try:
            data = [obj.to_dict() for obj in objs]
        except TypeError:
            data = [objs.to_dict()]
        return Response({'data': data}, content_type='application/json')
Ejemplo n.º 5
0
def release_coas(request):
    """Release certificates of analysis to the client."""

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # Restrict approving certificates to QA and owners.
    qa = claims.get('qa', [])
    owner = claims.get('owner', [])
    if org_id not in owner and org_id not in qa:
        message = f'Your must be an owner or quality assurance manager of this organization for this operation.'
        return Response({'error': True, 'message': message}, status=403)

    # Get the samples.
    posted_data = loads(request.body.decode('utf-8'))
    sample_ids = posted_data['sample_ids']

    # Update the certificate_status in Firestore.

    # Send (email and/or text) to the client's recipients.

    return NotImplementedError
Ejemplo n.º 6
0
def post_coas(request):
    """Post certificates of analysis to the state traceability system."""

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # Restrict approving certificates to QA and owners.
    qa = claims.get('qa', [])
    owner = claims.get('owner', [])
    if org_id not in owner and org_id not in qa:
        message = f'Your must be an owner or quality assurance manager of this organization for this operation.'
        return Response({'error': True, 'message': message}, status=403)

    # Get sample IDs.
    posted_data = loads(request.body.decode('utf-8'))
    sample_ids = posted_data['sample_ids']

    # Format data for API requests.

    # Post certificates 1 by 1.

    return NotImplementedError
Ejemplo n.º 7
0
def items(request):
    """Get, update, and delete items for a given license number."""

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        return Response({'error': True, 'message': AUTH_ERROR}, status=403)

    # Get the parameters.
    _, project_id = google.auth.default()
    license_number = request.query_params.get('license')
    org_id = request.query_params.get('org_id')
    version_id = request.query_params.get('version_id')
    if not license_number or not org_id:
        message = 'Parameters `license` and `org_id` are required.'
        return Response({'error': True, 'message': message}, status=403)

    # Initialize Metrc.
    track = initialize_metrc(project_id, license_number, version_id)

    # Get data.
    if request.method == 'GET':
        objs = track.get_items(license_number=license_number, uid='243821')
        data = [obj.to_dict() for obj in objs]
        print('Retrieved the data:', data)
        return Response({'data': data}, content_type='application/json')
Ejemplo n.º 8
0
def employees(request):
    """Get a licenses employees from Metrc.
    Args:
        request (HTTPRequest): A `djangorestframework` request.
    """

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        message = 'Authentication failed. Please use the console or provide a valid API key.'
        return Response({'error': True, 'message': message}, status=403)
    _, project_id = google.auth.default()
    license_number = request.query_params.get('name')

    # Optional: Figure out how to pre-initialize a Metrc client.

    # Get Vendor API key using secret manager.
    # FIXME: Determine where to store project_id, secret_id, and version_id.
    vendor_api_key = access_secret_version(project_id=project_id,
                                           secret_id='metrc_vendor_api_key',
                                           version_id='1')

    # TODO: Get user API key using secret manager.
    user_api_key = access_secret_version(project_id=project_id,
                                         secret_id=f'{license_number}_secret',
                                         version_id='1')

    # Create a Metrc client.
    track = authorize(vendor_api_key, user_api_key)

    # Make a request to the Metrc API.
    data = track.get_employees(license_number=license_number)

    # Return the requested data.
    return Response({'data': data}, content_type='application/json')
Ejemplo n.º 9
0
def users(request):
    """Get, update, or create user's data."""
    try:

        # Authenticate the user.
        claims = authenticate_request(request)
        print('User claims:', claims)
        uid = claims['uid']

        # Get the user's data.
        if request.method == 'GET':
            user_data = get_document(f'users/{uid}')
            response = {'success': True, 'data': user_data}
            return Response(response, content_type='application/json')

        # Edit user data if a 'POST' request.
        post_data = loads(request.body.decode('utf-8'))
        update_document(f'users/{uid}', post_data)
        create_log(
            ref=f'users/{uid}/logs',
            claims=claims,
            action='Updated user data.',
            log_type='users',
            key='user_data',
            changes=[post_data]
        )
        return Response({'success': True}, content_type='application/json')

    except:
        return Response(
            {'success': False},
            content_type='application/json',
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
Ejemplo n.º 10
0
def users(request):
    """Get, update, or create user's data."""
    print('Request to users endpoint!')
    try:

        # Authenticate the user.
        claims = authenticate_request(request)

        # Get user data.
        if request.method == 'GET':
            user_data = get_document(f'users/{claims["uid"]}')
            return Response(user_data, content_type='application/json')

        # Edit user data.
        if request.method == 'POST':

            # Get the user's ID.
            post_data = loads(request.body.decode('utf-8'))
            uid = claims['uid']
            post_data['uid'] = uid

            # Update the user's data, create a log, and return the data.
            try:
                update_document(f'users/{uid}', post_data)
                create_log(ref=f'users/{uid}/logs',
                           claims=claims,
                           action='Updated user data.',
                           log_type='users',
                           key='user_data',
                           changes=[post_data])
                return Response(post_data, content_type='application/json')

            except:

                # Create the user's data, create a log, and return the data.
                user_email = post_data['email']
                user = {
                    'email': user_email,
                    'created_at': utils.get_timestamp(),
                    'uid': post_data['uid'],
                    'photo_url':
                    f'https://robohash.org/${user_email}?set=set5',
                }
                update_document(f'users/{uid}', post_data)
                create_log(f'users/{uid}/logs', claims, 'Created new user.',
                           'users', 'user_data', [post_data])
                return Response(user, content_type='application/json')

    except:

        # Return a server error.
        return Response({'success': False},
                        content_type='application/json',
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Ejemplo n.º 11
0
def employees(request):
    """Get employees for a given license number."""

    # Authenticate the user.
    claims = authenticate_request(request)
    if not claims:
        return Response({'error': True, 'message': AUTH_ERROR}, status=403)
    _, project_id = google.auth.default()
    license_number = request.query_params.get('license')
    version_id = request.query_params.get('version_id')

    # Initialize Metrc.
    track = initialize_metrc(project_id, license_number, version_id)

    # Make a request to the Metrc API.
    objs = track.get_employees(license_number=license_number)
    data = [obj.to_dict() for obj in objs]

    # Return the requested data.
    return Response({'data': data}, content_type='application/json')
Ejemplo n.º 12
0
def analytics(request):
    """Get cannabis analytics."""

    # Authenticate the user.
    claims = authenticate_request(request)
    try:
        uid = claims['uid']
    except KeyError:
        message = 'Your request was not authenticated. Ensure that you have a valid session or API key.'
        return Response({'error': True, 'message': message}, status=401)

    # GET pre-defined analytics.
    if request.method == 'GET':
        return Response({'success': True, 'data': {'pre_existing_analytics': True}}, status=200)

    # POST request to get analytics given inputs.
    elif request.method == 'POST':
        posted_data = loads(request.body.decode('utf-8'))
        print('Posted data:', posted_data)
        return Response({'success': True, 'data': {'analytics': posted_data}}, status=200)
Ejemplo n.º 13
0
def delete_license(request, *args, **argv): #pylint: disable=unused-argument
    """Delete a license from an organization's licenses."""

    # Authenticate the user.
    _, project_id = google.auth.default()
    user_claims = authenticate_request(request)
    data = loads(request.body.decode('utf-8'))
    deletion_reason = data.get('deletion_reason', 'No deletion reason.')
    license_number = request.query_params.get('license')
    org_id = request.query_params.get('license')
    if not license_number or not org_id:
        message = 'Parameters `license` and `org_id` are required.'
        return Response({'error': True, 'message': message}, status=403)

    # Delete the license data and redact the secret.
    doc = get_document(f'organizations/{org_id}')
    existing_licenses = doc['licenses']
    licenses = []
    for license_data in existing_licenses:
        license_number = license_data['license_number']
        if license_data['license_number'] != license_number:
            licenses.append(license_data)
        else:
            add_secret_version(
                project_id,
                license_data['user_api_key_secret']['secret_id'],
                'redacted'
            )
    doc['licenses'] = licenses
    update_document(f'organizations/{org_id}', doc)

    # Create a log.
    create_log(
        ref=f'organizations/{org_id}/logs',
        claims=user_claims,
        action='License deleted.',
        log_type='traceability',
        key='delete_license',
        changes=[license_number, deletion_reason]
    )
    return JsonResponse({'status': 'success', 'message': 'License deleted.'})
Ejemplo n.º 14
0
def logs(request, log_id=None):
    """Get and create logs."""

    # Initialize and authenticate.
    model_id = log_id
    model_type = 'logs'
    model_type_singular = 'log'
    claims = authenticate_request(request)
    try:
        claims['uid']  #pylint: disable=pointless-statement
        owner = claims.get('owner', [])
        team = claims.get('team', [])
        quality_control = claims.get('qc', [])
        authorized_ids = owner + team + quality_control
    except KeyError:
        message = 'Your request was not authenticated. Ensure that you have a valid session or API key.'
        return Response({'error': True, 'message': message}, status=401)

    # Authorize that the user can work with the data.
    organization_id = request.query_params.get('organization_id')
    if organization_id not in authorized_ids:
        message = f'Your must be an owner, quality assurance, or a team member of this organization to manage {model_type}.'
        return Response({'error': True, 'message': message}, status=403)

    # GET data.
    if request.method == 'GET':
        docs = get_objects(request, authorized_ids, organization_id, model_id,
                           model_type)
        return Response({'success': True, 'data': docs}, status=200)

    # POST data.
    elif request.method == 'POST':
        data = update_object(request, claims, model_type, model_type_singular,
                             organization_id)
        if data:
            return Response({'success': True, 'data': data}, status=200)

    # Return an error message if post fails.
    message = 'Data not recognized. Please post either a singular object or an array of objects.'
    return Response({'error': True, 'message': message}, status=400)
Ejemplo n.º 15
0
def inventory(request, inventory_id=None):
    """Get, create, or update inventory."""

    # Initialize.
    model_id = inventory_id
    model_type = 'inventory'
    model_type_singular = 'item'

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # GET data.
    if request.method == 'GET':
        docs = get_objects(request, claims, org_id, model_id, model_type)
        return Response({'success': True, 'data': docs}, status=200)

    # POST data.
    elif request.method == 'POST':
        data = update_object(request, claims, model_type, model_type_singular,
                             org_id)
        if data:
            return Response({'success': True, 'data': data}, status=200)
        else:
            message = 'Data not recognized. Please post either a singular object or an array of objects.'
            return Response({'error': True, 'message': message}, status=400)

    # DELETE data.
    elif request.method == 'DELETE':
        success = delete_object(request, claims, model_id, model_type,
                                model_type_singular, org_id)
        if not success:
            message = f'Your must be an owner or quality assurance to delete {model_type}.'
            return Response({'error': True, 'message': message}, status=403)
        return Response({'success': True, 'data': []}, status=200)
Ejemplo n.º 16
0
def approve_coas(request):
    """Approve certificates of analysis for release after they have
    been reviewed."""

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # Restrict approving certificates to QA and owners.
    qa = claims.get('qa', [])
    owner = claims.get('owner', [])
    if org_id not in owner and org_id not in qa:
        message = f'Your must be an owner or quality assurance manager of this organization for this operation.'
        return Response({'error': True, 'message': message}, status=403)

    # Require pin.
    uid = claims['uid']
    post_data = loads(request.body.decode('utf-8'))
    pin = post_data['pin']
    message = f'{pin}:{uid}'
    app_secret = get_document('admin/api')['app_secret_key']
    code = sha256_hmac(app_secret, message)
    verified_claims = get_document(f'admin/api/pin_hmacs/{code}')
    if not verified_claims:
        return JsonResponse({'error': True, 'message': 'Invalid pin.'})
    elif verified_claims.get('uid') != uid:
        return JsonResponse({'error': True, 'message': 'Invalid pin.'})

    # Call generate_coas
    # - Make sure to fill-in approvers signature.
    # Update the sample's certificate_status.

    return NotImplementedError
Ejemplo n.º 17
0
def review_coas(request):
    """Review certificates of analysis so that they can be approved
    and released."""

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # Require pin.
    error_response = verify_user_pin(request)
    print(error_response)
    if error_response.status_code != 200:
        return error_response

    # Call generate_coas
    # - Make sure to fill-in reviewers signature.

    # Update the sample's certificate_status.

    return NotImplementedError
Ejemplo n.º 18
0
def join_organization(request):
    """Send the owner of an organization a request for a user to join."""

    # Identify the user.
    claims = authenticate_request(request)
    uid = claims['uid']
    user_email = claims['email']
    post_data = loads(request.body.decode('utf-8'))
    organization = post_data.get('organization')

    # Return an error if the organization doesn't exist.
    query = {'key': 'organization', 'operation': '==', 'value': organization}
    organizations = get_collection('organizations', filters=[query])
    if not organizations:
        message = 'Organization does not exist. Please check the organization name and try again.'
        return Response({'success': False, 'message': message}, status=400)

    # Send the owner an email requesting to add the user to the organization's team.
    org_email = organizations[0]['email']
    text = f"A user with the email address {user_email} would like to join your organization, \
        {organization}. Do you want to add this user to your organization's team? Please \
        reply YES or NO to confirm."

    paragraphs = []
    # TODO: Generate confirm, decline, and unsubscribe links with HMACs from user's uid and owner's uid.
    user_hmac = ''
    owner_hmac = ''
    # Optional: Find new home's for endpoints in api and cannlytics_website
    confirm_link = f'https://console.cannlytics.com/api/organizations/confirm?hash={owner_hmac}&member={user_hmac}'
    decline_link = f'https://console.cannlytics.com/api/organizations/decline?hash={owner_hmac}&member={user_hmac}'
    unsubscribe_link = f'https://console.cannlytics.com/api/unsubscribe?hash={owner_hmac}'
    # html_message = render_to_string('templates/console/emails/action_email_template.html', {
    #     'recipient': org_email,
    #     'paragraphs': paragraphs,
    #     'primary_action': 'Confirm',
    #     'primary_link': confirm_link,
    #     'secondary_action': 'Decline',
    #     'secondary_link': decline_link,
    #     'unsubscribe_link': unsubscribe_link,
    # })

    # TODO: Skip sending email if owner is unsubscribed.
    # send_mail(
    #     subject="Request to join your organization's team.",
    #     message=text,
    #     from_email=DEFAULT_FROM_EMAIL,
    #     recipient_list=LIST_OF_EMAIL_RECIPIENTS,
    #     fail_silently=False,
    #     html_message=html_message
    # )

    # Create activity logs.
    # create_log(f'users/{uid}/logs', claims, 'Requested to join an organization.', 'users', 'user_data', [post_data])
    # create_log(f'organization/{uid}/logs', claims, 'Request from a user to join the organization.', 'organizations', 'organization_data', [post_data])

    message = f'Request to join {organization} sent to the owner.'
    return Response({
        'success': True,
        'message': message
    },
                    content_type='application/json')
Ejemplo n.º 19
0
def create_coas(request):
    """Generate certificates of analysis."""

    # Authenticate the user.
    claims = authenticate_request(request)
    # FIXME: Get `org_id`
    org_id = None
    if claims.get('user') is None:
        message = 'Authentication failed.'
        return Response({'success': False, 'data': message}, status=401)

    # Require pin.
    error_response = verify_user_pin(request)
    print(error_response)
    if error_response.status_code != 200:
        return error_response

    # Get posted samples.
    posted_data = loads(request.body.decode('utf-8'))
    sample_ids = posted_data['sample_ids']

    # Create certificates for each sample.
    data = []
    for sample_id in sample_ids:

        # Get the sample data.
        sample_data = get_document(
            f'organizations/{org_id}/samples/{sample_id}')

        # Get the results for each sample. If there are no results,
        # then get the measurements for each sample and calculate
        # the results for each sample. Add a empty dictionary if missing everything.
        sample_results = get_collection(f'organization/{org_id}/results',
                                        order_by='updated_at',
                                        desc=True,
                                        filters=[{
                                            'key': 'sample_id',
                                            'operation': '==',
                                            'value': sample_id
                                        }])
        if not sample_results:
            sample_results = calculate_results(request)
            if not sample_results:
                sample_results = [{}]

        # Define the certificate context.
        context = {**sample_data, **sample_results[0]}

        # Get the certificate template.
        template_name = sample_data.get('coa_template_ref', DEFAULT_TEMPLATE)

        # FIXME:
        # Create the PDF, keeping the data.
        # Efficiency gain: Keep the template in /tmp so they don't have
        # to be downloaded each iteration.
        certificate = generate_coas(
            context,
            coa_template=template_name,
            # output_pages=pages,
            # limits=limits
        )
        data.append(certificate)

    # Return list of certificate data.
    return Response({'data': data}, status=200)
Ejemplo n.º 20
0
def organizations(request, organization_id=None, type='lab'):
    """Get, create, or update organizations.
    E.g.
        ```
        organization = {
                'owner': [],
                'name': '',
                'license': '',
                'type': '',
                'team': [],
                'support': '',
            }
        ```
    """

    # Get endpoint variables.
    model_type = 'organizations'
    _, project_id = google.auth.default()
    claims = authenticate_request(request)
    uid = claims['uid']
    print('User request to organizations:', uid)

    # Get organization(s).
    if request.method == 'GET':

        # Get organization_id parameter
        if organization_id:
            print('Query organizations by ID:', organization_id)
            data = get_document(f'{model_type}/{organization_id}')
            print('Found data:', data)
            if not data:
                message = 'No organization exists with the given ID.'
                return Response({
                    'error': True,
                    'message': message
                },
                                status=404)
            elif data['public']:
                return Response({'data': data}, status=200)
            elif uid not in data['team']:
                message = 'This is a private organization and you are not a team member. Request to join before continuing.'
                return Response({
                    'error': True,
                    'message': message
                },
                                status=400)
            else:
                return Response({'data': data}, status=200)

        # TODO: Get query parameters.
        keyword = request.query_params.get('name')
        if keyword:
            print('Query by name:', keyword)
            query = {'key': 'name', 'operation': '==', 'value': keyword}
            docs = get_collection(model_type, filters=[query])
            return Response({'data': docs}, status=200)

        # Get all of a user's organizations
        else:
            query = {
                'key': 'team',
                'operation': 'array_contains',
                'value': uid
            }
            docs = get_collection(model_type, filters=[query])
            return Response({'data': docs}, status=200)

        # Optional: Get list of other organizations.
        # Check if user is in organization's team, otherwise,
        # only return publically available information.

        # Optional: Try to get facility data from Metrc.
        # facilities = track.get_facilities()

    # Create or update an organization.
    elif request.method == 'POST':

        # Update an organization with the posted data if there is an ID.
        data = loads(request.body.decode('utf-8'))
        if organization_id:

            # Return an error if the organization already exists
            # and the user is not part of the organization's team.
            doc = get_document(f'{model_type}/{organization_id}')
            if not doc:
                message = 'No data exists for the given ID.'
                return Response({
                    'error': True,
                    'message': message
                },
                                status=400)

            organization_id = doc['uid']
            team_list = claims.get('team', [])
            owner_list = claims.get('owner', [])
            if uid not in team_list and organization_id not in owner_list:
                message = 'You do not currently belong to this organization. Request to join before continuing.'
                return Response({
                    'error': True,
                    'message': message
                },
                                status=400)

            # If an organization already exists, then only the owner
            # can edit the organization's team.
            if uid != doc['owner']:
                data['team'] = doc['team']

            # Store posted API keys as secrets.
            # FIXME: Update licenses if they are being edited.
            new_licenses = data.get('licenses')
            if new_licenses:
                licenses = doc.get('licenses', [])
                for license_data in new_licenses:
                    license_number = license_data['license_number']
                    secret_id = f'{license_number}_secret'
                    try:
                        create_secret(project_id, secret_id,
                                      license_data['user_api_key'])
                    except:
                        pass
                    secret = add_secret_version(project_id, secret_id,
                                                license_data['user_api_key'])
                    version_id = secret.split('/')[-1]
                    license_data['user_api_key_secret'] = {
                        'project_id': project_id,
                        'secret_id': secret_id,
                        'version_id': version_id,
                    }
                    del license_data['user_api_key']
                    licenses.append(license_data)
                doc['licenses'] = licenses

        # Create organization if it doesn't exist
        # All organizations have a unique `organization_id`.
        else:
            doc = {}
            organization_id = slugify(data['name'])
            doc['organization_id'] = organization_id
            doc['team'] = [uid]
            doc['owner'] = uid

            # Identify created organization type.
            doc['type'] = type

            # All organizations start with the standard data models.
            # FIXME: Remove data models that have permissions
            # if the user does not have sufficient claims.
            data_models = get_collection('public/state/data_models')
            for data_model in data_models:
                key = data_model['key']
                update_document(
                    f'{model_type}/{organization_id}/data_models/{key}',
                    data_model)

        # Create or update the organization in Firestore.
        entry = {**doc, **data}
        print('Entry:', entry)
        update_document(f'{model_type}/{organization_id}', entry)

        # FIXME:
        # On organization creation, the creating user get custom claims.
        update_custom_claims(uid,
                             claims={
                                 'owner': organization_id,
                                 'team': organization_id
                             })

        # TODO:  Owners can add other users to the team and
        # the receiving user then gets the claims.
        # team: [organization_id, ...]

        # Create activity log.
        changes = [data]
        create_log(f'{model_type}/{uid}/logs',
                   claims=claims,
                   action='Updated organization data.',
                   log_type=model_type,
                   key=f'{model_type}_data',
                   changes=changes)

        return Response({
            'data': entry,
            'success': True
        },
                        content_type='application/json')

    elif request.method == 'DELETE':

        # TODO: Only user's with organization_id in owner claim can delete the organization.

        return Response({'error': 'not_implemented'},
                        content_type='application/json')